local _ENV = hf_setenv('fishingtable',true)
-------------------------------
local skynet = require "skynet"
local utils = require "utils"
local proxypack = require "proxypack"
local msgdef = require "msgdef"
local pb = require 'protobuf'
local cjson = require "cjson"
local server_def = require "server_def"
local util = require "util"
local table_def = require "table_def"
local sharedata = require "skynet.sharedata"
local error_code = require "error_code"
local reason = require "reason"
local fishing_entity = require "fishing.fishing_entity"
local game_def = require "game_def"
local cocall = require "cocall"
local constant = require "constant"
local system_store = require "system_store"
local game_robot = require "fishing.fishing_robot"
local expand = require("expand") --老游戏功能拓展

local table_insert = table.insert
local table_remove = table.remove
local math_random = math.random
local math_floor = math.floor
local math_sqrt = math.sqrt
local math_abs = math.abs

local MAX_FISH_ENTITYS      = 100
local MAX_BULLET_ENTITYS    = 30
local FISH_DISTANCE         = 20        --鱼间隔(防止鱼太拥挤)
local CHANGE_SCENE_TIME     = 2.5       --切换场景时间(秒)

local MAX_ROBOT_NUM         = 1
local MAX_ROBOT_COINS       = 100
local MIN_ROBOT_COINS       = 50

local MAX_CATCH_FISH_NUM    = 4
local MIN_POWER             = 1
----------------特殊鱼id------------
local FISH_SEPCIAL_MERMAID     = 9000
local FISH_SEPCIAL_DEVIL       = 9001

----------------鱼类型---------------
local FISH_TYPE_SMALL           = 1
local FISH_TYPE_MUDIUM          = 2
local FISH_TYPE_BIG             = 3
local FISH_TYPE_SEPCIAL         = 9
-----------------------
local FISH_BOOM_TIME            = 180
------------------------------------
local GAME_STATUS_NORMAL        = 1 
local GAME_STATUS_BOOM          = 2
local GAME_STATUS_BOOM_SEND     = 3
local GAME_STATUS_BOOM_MSGHINT  = 4 
local GAME_STATUS_SCENE         = 5

local RATE_SCALE                = 10000
----------------------
local REGISTER_CLIENT_FD    = 0
local ROBOT_CLIENT_FD       = -1
local OFFLINE_CLIENT_FD     = -2

local MERMAID_BOSS_STATUS_NOR = 0
local MERMAID_BOSS_STATUS_NTF = 1

--高级鱼刷新间隔
local SENIOR_REFRESH_INTERVAL = 5
--鱼积分大鱼20 发送广播
local HORSE_MESSAGE_SCORE = 20

local HORSE_MESSAGE_JUNIOR = 8      --初级场广播id
local HORSE_MESSAGE_MIDDLE = 9     --中级场广播id
local HORSE_MESSAGE_SENIOR = 10     --高级级场广播id

local TRIGGER_STATUS_NORMAL = 1     --正常
local TRIGGER_STATUS_ADJUST = 2     -- 触发调整奖池
local TRIGGER_STATUS_DODGE  = 3      --打不中鱼



-- local feilong_win_lose = 0
--------------------common function----------------------------
function init(...)
    global_configs         = nil
    ordered_players        = {}            --坐下的玩家的顺序
    table_players          = {}            --标记房间所有玩家的clientId
    player_info_list       = {}            --玩家列表
    robot_manager          = {}            ---机器人
    enter_robot_map        = {}
    self_game_type         = nil
    self_table_id          = nil
    self_table_type        = nil
    this_table_gid         = nil
    self_table_pattern     = nil
    closing_server         = false
    stopping_server        = false

    fish_manager           = fishing_entity.new()
    bullet_manager         = {}
    touch_list             = {}
    lock_map               = {}
    unread_lock_map        = {}
    scene_id               = 1
    game_time              = 0.0
    scene_time             = 0.0
    last_time              = 0.0
    mermaid_sended_status  = MERMAID_BOSS_STATUS_NOR
    mermaid_sended_first   = false
    devilfish_sended       = false
    refresh_fish_boom      = false
    refresh_boom_delay     = false

    small_fish_count       = 0
    medium_fish_count      = 0
    big_fish_count         = 0
    small_fish_index       = nil
    medium_fish_index      = nil
    big_fish_index         = nil
    wait_status_time       = 0
    refresh_time           = 0
    boss_delay_time        = 0
    time_sync              = 0
    scene_gid              = 0
    refresh_group_time     = 0
    curr_game_status       = GAME_STATUS_NORMAL
    player_bill            = {}
    player_is_enter        = {}
    fish_boom_info         = {}

    fish_id_count          = 0
    fish_id_map            = {}
    last_senior_fish_time  = 0
    person_control_map     = {} --个人控制
    system_pool_trigger    = TRIGGER_STATUS_NORMAL --否触发调整池状态

    -- 调试用
    fish_map_count         = 0
    fish_add_count         = 0
    fish_reduce_count      = 0

    --触发财神驾到的金额
    caishen_coins_map = {}
    --财神红包结算时间
    caishen_end_time = {}    
    leave_interval_time = 0
    join_interval_time  = 0
    cur_target_player_num = 0

    --玩家消耗金币数和捕鱼获得金币数
    player_cost_map = {}
    player_win_map  = {}
    --玩家上升时期下降时期概率
    player_rate_map = {}
    gm_store_coins_add = 0

    player_card_record_coins_map = {} --牌局输赢钱

    ----
    hf_set_sentinel_end(_ENV)
    ---------------
    fish_manager:init_entitys(MAX_FISH_ENTITYS)
end

local handler = {}
local internal = {}

local function copy_table(t)
    local new_t = {}

    for k,v in pairs(t) do
        new_t[k] = v
    end

    return new_t
end

----机器人----
local function trigger_event(action,...)
    for _,AIobj in pairs(robot_manager) do
        local f = AIobj[action]
        if f then
            f(AIobj,...)
        end
    end
end

local function run_robots(new_robot_list)
    for _,robot_obj in pairs(new_robot_list) do
        skynet.fork(function()
            robot_obj:update()
        end)
    end
end

local function is_robot(uid)
    return enter_robot_map[uid] or false
end

local function robot_num()
    local robot_num = 0
    for uid in pairs(table_players) do
        if is_robot(uid) then
            robot_num = robot_num + 1
        end
    end

    return robot_num
end

local function put_back_robot(ret_map)
    R().robotmgr(1):send('.msg_handler','put_back_robots',ret_map)
end

local function have_player()
    for uid,_ in pairs(player_info_list) do
        if not is_robot(uid) then
            return true
        end
    end

    return false
end

local function have_robot()
    for uid,_ in pairs(player_info_list) do
        if is_robot(uid) then
            return true
        end
    end

    return false
end

local function get_max_capacity()
    return table_def.game_player_num[self_game_type]
end

local function find_empty_postion()
    local position = 1
    while ordered_players[position] do
        position = position + 1
    end

    if position > get_max_capacity() then
        return
    end

    return position
end

local function send_to_gateway(uid,client_fd,...)
    if not client_fd or client_fd <= 0 then
        return
    end

    return utils.send_to_gateway(0,uid,client_fd,...)
end

local function notify_others(action,excepted_uid,msg)
    --先广播给桌子上的人
    for uid, fd in pairs(table_players) do
        if uid ~= excepted_uid then
            send_to_gateway(uid,fd,action,msg)
        end
    end
end

local function notify_all(action,msg)
    return notify_others(action,nil,msg)
end

--把输赢发送到好友服(平台游戏概况)
local function sendLoseWinToFriendServer(system_lose_win)
    if system_lose_win == 0 then return end            
    -- feilong_win_lose = feilong_win_lose + system_lose_win
    -- print("___5________feilog______all_bet____", feilong_win_lose)   
    R().friendsvr(1):send('.info_mgr', 'set_room_summary', self_table_type, {table_type = self_table_type, lose_win = system_lose_win})
end  

local function set_client_fd(uid,client_fd)
    table_players[uid] = client_fd
end

local function get_client_fd(uid)
    return table_players[uid]
end

local function remove_client_fd(uid)
    table_players[uid] = nil
end

local function remove_player(uid)
    player_info_list[uid] = nil
end

local function add_player(uid,player_info)
    player_info_list[uid] = player_info
end

local function get_player(uid)
    return player_info_list[uid]
end

local function get_curr_guns_info(uid)
    local conf = {}
   local player_info = get_player(uid)
   for _,guns_info in pairs(global_configs.fishing_guns) do
        if tonumber(guns_info.id) == player_info.curr_guns then
            conf = guns_info
            break
        end
    end
    return conf
end

local function get_player_num()
    local num = 0
    for _,v in pairs(ordered_players) do
        if v then
            num = num + 1
        end
    end

    return num
end

local function get_extra_bill_info(uid)
    local t = {game_type=self_game_type,table_type=self_table_type,is_robot=is_robot(uid)}
    local player_info = get_player(uid)
    if not player_info then
        return t
    end

    t.client_version = player_info.client_version
    t.channel = player_info.channel
    t.device_id = player_info.device_id
    t.device_brand = player_info.device_brand
    t.os_system = player_info.os_system
    t.platform = player_info.platform    
    return t
end

local function add_coins(uid,coins,reason,...)
    local ok,succ,ret = R().basesvr{key=uid}:call('.msg_handler','add_coins',uid,coins,reason,get_extra_bill_info(uid))
    if not ok then
        errlog(uid,'failed to add_coins ok is nil',coins)
        return
    end
    if not succ then
        errlog(uid,'failed to add_coins succ is nil',coins)
        return
    end

    return {
        curr_coins = ret.curr,
        chged = ret.chged
    }
end

local function reduce_coins(uid,coins,reason,...)
    local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler','reduce_coins',uid,coins,reason,get_extra_bill_info(uid))
    if not ok then
        errlog(uid, "reduce_coins error because ok is nil")
        return
    end

    if not succ then
        errlog(uid, "reduce_coins error because succ is nil")
        return
    end
    return {
        curr_coins = ret.curr,
        chged = ret.chged
    }
end

local function watch_session(game_session,uid,observing)
    if not game_session or game_session <= 0 then
        return
    end
    local gateway_id = game_session >> 31
    local request
    if observing then
        request = 'observe_fd'
    else
        request = 'unobserve_fd'
    end

    R().gateway(gateway_id):send('.watchdog','tablesvr',request,R().get_source(),game_session,uid)
end

local function update_friend_info(uid,game_type)
    if not game_type then
        game_type = self_game_type
    end
    if not is_robot(uid) then
        R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=game_type,curr_table_type = self_table_type})
    end
end

local function lock_one_player(uid)
    if is_robot(uid) then return end
    local ok,succ = R().exdbsvr(1):call('.tlock_mgr','set_on_table',uid,this_table_gid,this_table_gid)
    if not ok then
        errlog(uid,'lfdj failed to set_on_table')
        return
    end

    if not succ then
        return
    end

    return true
end


--玩这实时输赢op
function realTimeWinLose(uid, leave_time)
    dbglog("realTimeWinLose",uid)
    if is_robot(uid) then return end
    local player_info = player_info_list[uid]
    if not player_info.enter_time then 
        errlog("__________player_info.enter_time__是空的____", uid, player_info)
        return 
    end    
    local table_gid = player_info.enter_time .. "_" .. self_table_id .."_"..uid
    leave_time = leave_time or 0
    if player_info.all_win_lose == 0 then 
        --没产生流水就不记录了
        return
    end
    local data = {
        op = "user_leave_game",
        uid = uid,
        table_gid = table_gid, --唯一标记
        table_type = self_table_type,
        name = player_info.name,        
        enter_coins = player_info.enter_coins, --进入时身上金币
        enter_safe_coins = player_info.enter_safe_coins, --进入时保险箱金币 
        enter_time = player_info.enter_time, --进入时间
        leave_time = leave_time, --离开时间
        leave_coins = player_info.coins, --离开时身上金币
        leave_safe_coins = player_info.safe_box, --离开时保险箱金币
        win_lose = player_info.all_win_lose, --在玩游戏内产生的输赢（
        free = player_info.all_free, --玩游戏交上的台费
    }
    dbglog("_______user_leave_game_____",  data)
    billlog(data)
end


local function unlock_one_player(uid)
    if is_robot(uid) then return end
    R().exdbsvr(1):send('.tlock_mgr','unset_on_table',uid,this_table_gid)
end

local function unlock_all_players()
    for uid,_ in pairs(table_players) do
        unlock_one_player(uid)
    end
end

local function notify_matchsvr_table_stats(is_delete)
    local table_stats = {}
    if is_delete then
        table_stats.table_gid = this_table_gid
        table_stats.table_type = self_table_type
        R().newmatchsvr(1):send('.table_mgr','delete_table_stats',table_stats)
    else
        table_stats.table_type = self_table_type
        table_stats.left_num = get_max_capacity() - get_player_num()
        table_stats.table_gid = this_table_gid
        table_stats.table_pattern = self_table_pattern
        R().newmatchsvr(1):send('.table_mgr','update_table_stats',table_stats)
    end
end

local function get_guns_id(lists,uid,vip_level)
    print("get_vip_level=======222",uid,vip_level,is_robot(uid))
    local curr_guns
    for _,guns_info in pairs(global_configs.fishing_guns) do
        local fd = table_players[uid] or 0
        if fd == ROBOT_CLIENT_FD then --机器人进来根据vip等级设置炮台
            if (vip_level or 0) >= (guns_info.vip_level or 0) then
                curr_guns = guns_info.id
            end
        else --玩家进来默认最初级的炮台
            if (guns_info.vip_level or 0) == 0 and  (guns_info.validity_time or 0) == 0 then
                curr_guns = guns_info.id
            end
        end
    end
    if not curr_guns then
        errlog("connot find free guns_id")
    end

    print("get_vip_level=======333",uid,curr_guns)

    if not is_robot(uid) then
        local ok,guns_id = R().basesvr{key=uid}:call('.msg_handler','get_fish_gun',uid)
        curr_guns = guns_id or curr_guns
    end

    return curr_guns
end

local function get_fire_interval(guns_id)
    for _,guns_info in pairs(global_configs.fishing_guns) do
        if guns_info.id == guns_id then
            return guns_info.fire_interval
        end
    end
end

local function init_player(uid,is_robot)
    local player_info = assert(get_player(uid))
    local roomdata = global_configs.roomdata[self_table_type]

    enter_robot_map[uid] = is_robot
    player_info.guns_list = player_info.guns_list or {}
    player_info.curr_power = global_configs.fishing_fire[1] --* roomdata.multiple
    player_info.curr_guns = get_guns_id(player_info.guns_list,uid,player_info.vip_level)
    player_info.curr_fire_interval = get_fire_interval(player_info.curr_guns)
end

local function load_robot(robot_num)
    local roomdata = global_configs.roomdata[self_table_type]
    if not roomdata or not roomdata.open_robot then
        errlog(self_table_type,"load robot fail ---> can not open robot")
        return
    end

    local robot_type = roomdata.robot_type or -1
    local robot_info = global_configs.robot[robot_type]
    if not robot_info then
        errlog(self_table_type,'load_robot fail because robot is nil',robot_type)
        return
    end

    --判断当前人数
    local player_num = get_player_num()
    if player_num >= get_max_capacity() then
        return
    end

    --已经达到预期人数,不需要加载机器人
    print("load_robot============111",cur_target_player_num,player_num,tostring_r(ordered_players))
    if not robot_num and cur_target_player_num <= player_num then
        return
    end
    print("load_robot============222",cur_target_player_num,player_num,robot_num)

    local conis_limit = {robot_info.min_coin,robot_info.max_coin}
    local load_num = robot_num or 1
    local ok,succ,robot_list = R().robotmgr(1):call('.msg_handler','get_robots',load_num,robot_type,conis_limit)
    if not ok or not succ then
        errlog("load robot is fail",robot_type)
        print_r(conis_limit)
        return
    end

    --再次检查人数是否已经满了 如果满了将机器人送回
    local curr_num = get_player_num()
    if curr_num >= get_max_capacity() then
        put_back_robot(robot_list)
        return
    end
    
    print_r(robot_list)

    local curr_time = util.get_now_time()
    local new_robot_list = {}
    local end_idx
    for index, robot_info in pairs(robot_list) do
        local robot_uid = robot_info.uid
        local ok,vip_level = R().basesvr{key=robot_uid}:call('.msg_handler', 'get_vip_level',robot_uid)
        print("get_vip_level==============111",ok,vip_level)
        local player_info = {
            uid = robot_uid,
            name = robot_info.name,
            coins = robot_info.coins,
            sex = robot_info.sex,
            icon = robot_info.icon,
            coins_type = robot_info.coins_type,
            last_chat_time = 0,
            last_ping_time = curr_time,
            vip_level = vip_level or 0
        }

        assert(not table_players[robot_uid],robot_uid)
        assert(not player_info_list[robot_uid],robot_uid)

        local position = find_empty_postion()
        if not position then
            end_idx = index
            errlog("load robot postion is max")
            break
        end

        ordered_players[position] = robot_uid
        player_info.position = position
        table_insert(touch_list,robot_uid)
        add_player(robot_uid,player_info)
        set_client_fd(robot_uid,ROBOT_CLIENT_FD)
        init_player(robot_uid,true)
        local robot_obj = game_robot.new(robot_uid,player_info,robot_type,skynet.self(),ROBOT_CLIENT_FD,roomdata.multiple)
        robot_manager[robot_uid] = robot_obj
        table_insert(new_robot_list,robot_obj)
        trigger_event('on_register',robot_uid,bullet_manager)
        print(robot_uid,"load_robot ok ")
    end

    notify_matchsvr_table_stats()
    run_robots(new_robot_list)

    local failed_list = {}
    if end_idx then
        for i = end_idx,#robot_list do
            local robot_data = robot_list[i]
            table_insert(failed_list,robot_data)
        end

        if #failed_list > 0 then
            put_back_robot(failed_list)
        end
    end
end

local function put_back_robots()
    for uid, _ in pairs(player_info_list) do
        if is_robot(uid) and robot_manager[uid] then
            robot_manager[uid]['close_server'](robot_manager[uid])
            print("push_robot")
        end
    end
end

local function delay_time_sec(curr_msec,sec)
    wait_status_time = curr_msec + sec * 1000
end

----
local function add_fish_count(fish_id,client_id,curr_msec,score)
    local fish_type = math_floor(fish_id / 1000)
    --中鱼 和 大鱼 加入机器人 
    if FISH_TYPE_SMALL == fish_type then
        small_fish_count = small_fish_count + 1
        fish_add_count = fish_add_count + 1
        if score >= 10 then
            trigger_event('add_lock_fish',client_id,curr_msec,score)
        end
    elseif FISH_TYPE_MUDIUM == fish_type then
        medium_fish_count = medium_fish_count + 1
        fish_add_count = fish_add_count + 1
        trigger_event('add_lock_fish',client_id,curr_msec,score)
    elseif FISH_TYPE_BIG == fish_type then
        big_fish_count = big_fish_count + 1
        fish_add_count = fish_add_count + 1
        trigger_event('add_lock_fish',client_id,curr_msec,score)
    end
end

local function reduce_fish_count(fish_id)
    local fish_type = math_floor(fish_id / 1000)
    if FISH_TYPE_SMALL == fish_type then
        small_fish_count = small_fish_count - 1
        fish_reduce_count = fish_reduce_count - 1
    elseif FISH_TYPE_MUDIUM == fish_type then
        medium_fish_count = medium_fish_count - 1
        fish_reduce_count = fish_reduce_count - 1
    elseif FISH_TYPE_BIG == fish_type then
        big_fish_count = big_fish_count - 1
        fish_reduce_count = fish_reduce_count - 1
    end
end

local function get_fish_id()
    if fish_id_count > 65535 then
        fish_id_count = 0
    end

    fish_id_count = fish_id_count + 1
    return fish_id_count
end

local function set_fish_id(fish_entify)
    local fish_id = get_fish_id()
    fish_id_map[fish_id] = fish_entify.id
    return fish_id
end

local function get_fish_entity(fish_id)
    local entify_id = fish_id_map[fish_id]
    local fish_entify
    if entify_id then
        fish_entify = fish_manager:get_entity(entify_id)
        if fish_entity and fish_entity.index_id == constant.INVALID_ID then
            print("get_fish_entity===not_find",fish_id)
            return
        end
    end

    return fish_entify
end

local function remove_fish_id(fish_id)
    local entify_id = fish_id_map[fish_id]
    if entify_id then
        local fish_entity = fish_manager:get_entity(entify_id)
        if  fish_entity and fish_entity.index_id ~= constant.INVALID_ID then
            fish_manager:delete_entity(entify_id)
            reduce_fish_count(fish_entity.type)
        end
    end

   fish_id_map[fish_id] = nil
end

local function remove_fish_idmap(fish_id)
   fish_id_map[fish_id] = nil
end

local function is_fish_exist(fish_id)
    if not fish_id_map[fish_id] then
        return false
    end

    return true
end

---
local function copy_fish(fish_entify)
    local fish_id = set_fish_id(fish_entify)
    return {
        id = fish_id,   --fish_entify.id,
        type = fish_entify.type,
        create_time =  math_floor(fish_entify.create_time),
        path = fish_entify.path,
        path_time = fish_entify.speed,
        point_offset = copy_table(fish_entify.point_offset),
    }    
end

local function copy_bullet(bullet_entify)
    return {
        id = bullet_entify.bullet_id,
        angle = bullet_entify.angle,
        create_time = math_floor(bullet_entify.create_time),
        power = bullet_entify.power,
        guns_id = bullet_entify.guns_id,
        speed = bullet_entify.speed,
    }
end

--根据vip等级获取炮台列表
local function get_guns_list_by_vip_level(cur_vip_level)
    local guns_list = {}
    for _, data in pairs(global_configs.fishing_guns) do
        --当前VIP等级 >= 炮台对应VIP等级
        if cur_vip_level >= (data.vip_level or 0) then
            table_insert(guns_list, {id = tonumber(data.id), end_time = 0})
        end
    end
    print_r(guns_list)
    return guns_list
end

local function stand_up(uid,pos)
    local player_info = assert(get_player(uid),'stand_up no player info' .. tostring(uid))

    if player_info.position ~= pos then
        return false,411
    end

    if ordered_players[pos] ~= uid then
        return false,410
    end

    ordered_players[pos] = EMPTY_SEAT
    player_info.position = nil
    return true
end

local function get_player_curr_coins(uid)
    if player_info_list[uid] then
        return player_info_list[uid].coins
    
    else
        local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        if not ok then
            errlog(uid,'get_player_curr_coins-->failed to get base_data')
            return 0
        end

        return base_data.coins
    end

    return 0
end


local function record_player_card_record(uid)
    if not player_card_record_coins_map[uid] then
        return
    end

    local add_score = player_card_record_coins_map[uid] or 0
    local curr = get_player_curr_coins(uid)
    local data = {uid = uid,left_score = curr,add_score = add_score,is_robot = is_robot(uid),pay_fee = 0}

    local winners = {}
    local losers  = {}
    if add_score >= 0 then
        table_insert(winners,data)
    elseif add_score < 0 then
        table_insert(losers,data)
    end
    
    local str_date = os.date("%Y%m%d%H%M%S")
    if have_player() then
        if next(winners) or next(losers) then
            billlog({
                op = "card_record",
                table_gid = str_date .. "_" .. self_table_id,
                game_type = self_game_type,table_type = self_table_type,
                begin_time = game_time,end_time = util.get_now_time(),
                winner_list = winners,loser_list = losers,system_win = -add_score,
                side_list = {},exinfo = {},
                total_num = get_player_num(),
                address = skynet.address(skynet.self()),
            })
        end
    end
    
    player_card_record_coins_map[uid] = nil --清掉个人牌局记录值
end

local function leave(uid)

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"leave----> can not find player")
        return false
    end
    
    record_player_card_record(uid) --离开记录个人牌局记录

    if player_info.position then
        stand_up(uid,player_info.position)
    end

    if not is_robot(uid) then
        if player_info.curr_guns then
            R().basesvr{key=uid}:send('.msg_handler','set_fish_gun',uid,player_info.curr_guns) --保存上次使用的炮台
        end
        update_friend_info(uid,0)
        watch_session(get_client_fd(uid),uid,false)
        skynet.send('.table_mgr','lua','leave',uid)
        unlock_one_player(uid)
        realTimeWinLose(uid, os.time())


        local uid = uid
        local bet_coins = player_info.all_bet
        local produce = player_info.all_bet + player_info.all_win_lose
        local win_lose = player_info.all_win_lose
        local free = player_info.all_free
        expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)        

        print("___4________feilog______all_bet____",uid, player_info.all_win_lose)
    else
        if robot_manager[uid] then
            robot_manager[uid]["on_exit"](robot_manager[uid])
            robot_manager[uid] = nil
        end
    end

    remove_client_fd(uid)
    remove_player(uid)
    notify_matchsvr_table_stats()
    if not is_robot(uid) then
        R().friendsvr(1):send(".info_mgr", "update_info", uid, { curr_game_type = 0 })
    end
    
    return true
end

-- local function dissmiss_table()
--     local uids = {}
--     local robots = {}
--     for uid,player_info in pairs(player_info_list) do
--         local game_session = table_players[uid]
--         local robot = is_robot(uid)
--         leave(uid)

--         local roomdata = global_configs.roomdata[self_table_type]
--         if robot and roomdata and roomdata.robot_type then
--             table_insert(robots,{type=roomdata.robot_type, uid=uid, coins=player_info.coins})
--         end
        
--         table_insert(uids,uid)
--     end

--     notify_matchsvr_table_stats(true)                                       --更新桌子
--     skynet.send('.table_mgr','lua','on_table_delete',self_table_id,uids)    --删除状态
--     --R().robotmgr(1):send('.msg_handler','put_back_robots',robots)           --归还机器人
--     --put_back_robot(robots)
--     --put_back_robots()
--     return true
-- end

local function robot_coins_check()
    local kick_robots = {}
    local roomdata = global_configs.roomdata[self_table_type]
    for uid,player_info in pairs(player_info_list) do
        if is_robot(uid) then
            if player_info.curr_power * roomdata.multiple >= player_info.coins then
                table_insert(kick_robots,uid)
            end
        end
    end

    for _,uid in pairs(kick_robots) do 
        print("kick_robots",uid)
        trigger_event('close_server',uid)
    end
end

-- local function check_close_table(curr_time)
--     if stopping_server then        
--         billlog({op = "stop_table",status = curr_status,password = self_password})
--         closing_server = true --直接关闭桌子
--     end

--     if not closing_server then
--         if curr_time - game_time <= 30 then --桌子刚启动30秒内不关桌
--             return
--         end
--     end

--     if not have_player() then --没有真人 就关闭桌子吧
--         closing_server = true
--         print("-----Non-existent person will close table----",self_game_type,self_table_id)
--     end

--     if closing_server == true then
--         local ok,ret = xpcall(dissmiss_table,debug.traceback)
--         if not ok then
--             errlog(ret)
--         end
        
--         billlog({op = "close_table",password = self_password})
--         dbglog('now delete this table',self_table_id)
--         skynet.exit()
--     end
-- end

local function get_player_enter_data(uid)
    --先拉取玩家信息
   local ok,base_data = R().basesvr{key=uid}:call('.msg_handler','get_base_data',uid)
   if not ok then
       errlog(uid,'failed to get base_data',uid)
       return
   end

   local ok,enter_data = R().hallsvr{key=uid}:call('.msg_handler','get_enter_data',uid)
   if not ok then
       errlog(uid,'failed to get enter_data')
       enter_data = {}
   end

   local player_info = {
       uid = base_data.uid,
       name = enter_data.name or '',
       coins = base_data.coins,
       icon = enter_data.icon or '',
       sex = enter_data.sex,
       personal_rate = base_data.hitrate,
       rtp_rate = base_data.person_rate,
       vip_level = base_data.vip_level,
       icon_border = enter_data.icon_border,
       --不再从数据库中读取玩家炮台信息 而改为仅根据配置来获取
       --guns_list = enter_data.guns_list,
       guns_list = get_guns_list_by_vip_level(base_data.vip_level),
       safe_box = base_data.safe_box,
   }


   return player_info
end

local function get_response_player_info(player_info)
    return {
        uid = player_info.uid,
        name = player_info.name,
        coins = player_info.coins,
        icon = player_info.icon,
        position = player_info.position,
        power = player_info.curr_power,
        curr_guns = player_info.curr_guns,
    }
end

local function get_enter_info(uid)
    local player_list = {}
    local bullet_list = {}
    local fish_list = {}
    local guns_list = {}
    local item_list = {}
    local lock_list = {}

    local multiple = 1
    local roomdata = global_configs.roomdata[self_table_type]
    if roomdata.multiple then
        multiple = roomdata.multiple
    end

    local now_sec, now_usec = util.get_now_time()
    local player_info = get_player(uid)

    local ok,winlose = R().basesvr{key=uid}:call('.msg_handler','get_winlose',uid)
    if not ok then
        errlog(uid,"get_winlose error")
        winlose = 0
    end

    player_info.winlose = winlose
    for uid,info in pairs(player_info_list) do
        local rsp_player_info = get_response_player_info(info)
        table_insert(player_list,rsp_player_info)

        local user_bullet = bullet_manager[uid]
        if user_bullet then
            for index,bullet_entity in pairs(user_bullet) do
                local rsp_bullet_info = copy_bullet(bullet_entity)
                rsp_bullet_info.uid = uid
                table_insert(bullet_list,rsp_bullet_info)
            end
        end
    end

    for fish_id,_ in pairs(fish_id_map) do
        local fish_entify = get_fish_entity(fish_id)
        if fish_entify then
            table_insert(fish_list,{id = fish_id,type = fish_entify.type,create_time =  math_floor(fish_entify.create_time),
                path = fish_entify.path, path_time = fish_entify.speed, point_offset = copy_table(fish_entify.point_offset),})
        end
    end
    -- for i=1,fish_manager:get_count() do
    --     local fish_entity = fish_manager:get_index_entity(i)
    --     table_insert(fish_list,copy_fish(fish_entity))
    -- end

    for uid,fish in pairs(lock_map) do
        table_insert(lock_list,{uid = uid,fish_id = fish})
    end

    print("-----------enter-----------",#fish_list)
    --print_r(fish_list)
    local conf = get_curr_guns_info(uid)
    local enter_info = {
        player_list = player_list,
        fish_list = fish_list,
        bullet_list = bullet_list,
        touch_list = touch_list,
        item_list = item_list,
        bullet_speed = global_configs.fishing_config.bullet_speed,
        server_time = math_floor((now_sec * 1000) + (now_usec / 1000)),
        position_num = get_max_capacity(),
        lock_info = lock_list,
        multiple = multiple,
        fire_interval = conf.fire_interval/100,
    }

    return {
        game_type = self_game_type,
        table_type = self_table_type,
        fishing_enter_info = enter_info,
        name = roomdata.name,
    }
end

local function notify_player_enter(uid)
    local player_info = assert(get_player(uid))
    local player = {
        uid = uid,
        name = player_info.name,
        position = player_info.position,
        coins = player_info.coins,
        icon = player_info.icon,
        sex = player_info.sex,
        curr_guns = player_info.curr_guns,
        power = player_info.curr_power,
        vip_level = player_info.vip_level,
        icon_border = player_info.icon_border
    }

    local play_effect = false
    local enter_word = ""
    local vip_level_conf = utils.getDataBykv(global_configs.vip,"level",player_info.vip_level or 0)
    if vip_level_conf and vip_level_conf.privilege[game_def.VIP_PRIVILEGE_TYPE_SIX] then
        play_effect = true
        enter_word = vip_level_conf.enter_word or ""
    end
    notify_all('fishing.NTF_ENTER',{play_effect = play_effect,player = player,enter_word = enter_word})
    if is_robot(uid) then
        notify_others('fishing.NTF_TOUCH_CRASH',uid,{uid_list = touch_list})
    end
end

local function clear_player_rate_info(uid)
    print("clear_player_rate_info==========",uid)
    local fish_store = global_configs.fishing_store[self_table_type]
    if not fish_store then
        return
    end
    player_rate_map[uid] = player_rate_map[uid] or {}

    local trigger_time_range = fish_store.rise_fall_hit.trigger_time_range
    
    local curr_time = util.get_now_time()
    player_rate_map[uid].trigger_time = curr_time + math_random(trigger_time_range[1],trigger_time_range[2])
    player_rate_map[uid].trigger_continue_time = 0
end

local function on_enter(uid,client_fd,msg)
    print("on_enter================111",uid,client_fd)
    local rsp_enter_info
    if closing_server then
        errlog(uid,'on_enter failed to closing_server!!')
        return false,error_code.FAILED_TO_MATCH_PLAYER
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,'on_enter failed to get player_info is nil')
        return false,-433
    end

    if player_is_enter[uid] then
        rsp_enter_info = get_enter_info(uid)
        return true,rsp_enter_info
    end
    
    if not player_info.position then
        local position = find_empty_postion()
        if not position then
            errlog(uid,'on_enter failed to get position is nil')
            return false,error_code.FAILED_TO_MATCH_PLAYER
        end

        ordered_players[position] = uid
        player_info.position = position
    end

    set_client_fd(uid, client_fd)
    init_player(uid,client_fd == ROBOT_CLIENT_FD)
    print("on_enter================3333",uid,client_fd)
    if client_fd == ROBOT_CLIENT_FD then
        print("on_enter================222",uid,client_fd)
        player_info.personal_rate = 1
        player_info.winlose = 0
        player_info.rtp_rate = 1
        --return true
    else
        local data = get_player_enter_data(uid)
        if data then
            player_info.name = data.name
            player_info.icon = data.icon
            player_info.coins = data.coins
            player_info.sex = data.sex
            player_info.roomcards = data.roomcards
            player_info.personal_rate = data.personal_rate
            player_info.rtp_rate = data.rtp_rate
            player_info.vip_level = data.vip_level
            player_info.icon_border = data.icon_border
            player_info.guns_list = data.guns_list
            player_info.safe_box = data.safe_box
            player_info.enter_coins = data.coins
            player_info.enter_time = os.time()
            player_info.enter_safe_coins = data.safe_box
            player_info.all_win_lose = 0
            player_info.all_free = 0
            player_info.all_produce = 0
            player_info.all_bet = 0


            player_info.os_system = data.os_system
            player_info.platform = data.platform            
        end

        player_info.client_version = msg.client_version
        player_info.channel = msg.channel
        player_info.device_id = msg.device_id
        player_info.device_brand = msg.device_brand
        player_info.cur_channel = msg.cur_channel
        watch_session(client_fd,uid,true)
        update_friend_info(uid)
        rsp_enter_info = get_enter_info(uid)
        player_is_enter[uid] = true

        clear_player_rate_info(uid)
    end

    print(uid,"----------enter--------------")
    --dbglog(player_info)
    
    return true,rsp_enter_info
end

local function get_fish_info(fish_id)
    local fish_type = math_floor(fish_id / 1000)
    if not global_configs.fishing_type then
        errlog("global_configs.fishing_type is nill")
        return
    end

    local fish_info
    if fish_type == FISH_TYPE_SMALL then
        if not global_configs.fishing_type.small_fish then
            return
        end

        fish_info = global_configs.fishing_type.small_fish[fish_id]
    elseif fish_type == FISH_TYPE_MUDIUM then
        if not global_configs.fishing_type.medium_fish then
            return
        end

        fish_info = global_configs.fishing_type.medium_fish[fish_id]
    elseif fish_type == FISH_TYPE_BIG then
        if not global_configs.fishing_type.big_fish then
            return
        end

        fish_info = global_configs.fishing_type.big_fish[fish_id]
    elseif fish_type == FISH_TYPE_SEPCIAL then
        if not global_configs.fishing_type.special_boss then
            return
        end

        fish_info = global_configs.fishing_type.special_boss[fish_id]
    end

    return fish_info
end

local function get_fish_score(fish_id)
    local fish_info = get_fish_info(fish_id)
    if fish_info then
        return fish_info.score
    end
    errlog("___________no_fhis_score___", fish_id)
    return 0
end

local function get_fish_rate(fish_id)
    local fish_info = get_fish_info(fish_id)
    if fish_info then
        return fish_info.rate,fish_info.threshold
    end

    return 1,0
end

local function get_catch_coe(uid)
    local result_coe = 1
    local player_info = get_player(uid)
    if not player_info.winlose then
        player_info.winlose = 0
    end

    local player_winlose = player_info.winlose
    local catch_coe = global_configs.fishing_catch_rate
    if not catch_coe  or not catch_coe[self_table_type] then
        errlog(uid,"config error! can not find catch_coe",self_table_type)
        return result_coe
    end

    catch_coe = catch_coe[self_table_type]
    if player_winlose < 0 then
        player_winlose = math_abs( player_winlose )
        local lose_coe = catch_coe.lose
        if lose_coe then
            for _,info in pairs(lose_coe) do 
                if info[1] <= player_winlose and player_winlose < info[2] then
                    result_coe = info[3]
                    break
                end
            end
        end
    elseif player_winlose > 0 then
        local lose_coe = catch_coe.win
        if lose_coe then
            for _,info in pairs(lose_coe) do 
                if info[1] <= player_winlose and player_winlose < info[2] then
                    result_coe = info[3]
                    break
                end
            end
        end
    end

    if not result_coe then
        errlog(uid,"get_catch_coe error! result_coe is nil",player_winlose)
        result_coe = 1
    end

    return result_coe
end
----------------------------------------------------------fishing


local function get_total_fish()
    return small_fish_count + medium_fish_count + big_fish_count
end

local function get_fish_arrang(fish_num,arrang_id)
    if not arrang_id then
        if global_configs.fishing_point then
            arrang_id = global_configs.fishing_point[fish_num]
            if arrang_id then
                arrang_id = arrang_id[math_random(1,#arrang_id)]
            end
        end
    end

    if not arrang_id then
        errlog("fishing_point config error,num:",fish_num)
        return
    end

    local fishing_arrang
    if global_configs.fishing_arrang then
        fishing_arrang = global_configs.fishing_arrang[arrang_id]
    end

    if not fishing_arrang then
        errlog("fishing_arrang config error,num:",fish_num," arrang_id: ",tostring(arrang_id))
        return 
    end

    return fishing_arrang
end

local function calculate_distance(x1,y1,x2,y2)
    return math_sqrt((x1-x2) * (x1-x2) + (y1-y2)* (y1-y2))
end

local function calculate_path(path_id)
    --print("---->",path_id)
    if global_configs.path_config then
        local path_info = global_configs.path_config[path_id]
        if not path_info then
            errlog(path_id," does not exist! ")
            return
        end

        local path_points = path_info.points
        if #path_points < 5 then
            errlog(path_id,"path_points  is not enough")
            print_r(path_points)
            return
        end

        local dis = calculate_distance(path_points[1],path_points[2],path_points[3],path_points[4])
        return #path_points / 2,dis
    end

    return
end
local function calculate_time(x,y,p,t)
    if math_abs(x) < 10 and math_abs(y) < 10 then
        return t + 1
    end

    local path_l,path_dis = calculate_path(p)
    if not path_l or not path_dis or path_dis == 0 then
        errlog(p,"calculate_time--> error",path_l,path_dis)
        return
    end

    local one_time = t / path_l
    local all_s = math_sqrt(x*x + y*y) / path_dis

    --print(x,y,"calculate_time--->",one_time,all_s,t,path_l)
    if x > 0 then
        return one_time * (path_l - all_s) + 1
    else
        return one_time * (all_s + path_l) + 1
    end

end

local function send_fish(curr_msec,fish_num,fish_path,fish_id,arrang_id)
    local fishing_arrang = get_fish_arrang(fish_num,arrang_id)
    if not fishing_arrang then
        errlog(fish_num,"can not find fishing_arrang",is_multi)
        return
    end

    local speed = 1.0
    if fish_path.path_speed and fish_path.path_speed > 0 then
        speed = fish_path.path_speed
    end

    local path_time = fish_path.path_time / speed
    local point = fishing_arrang.point
    local fish_list = {}
    for i = 1,fish_num do
        local point_info = point[i]
        if not point_info then
            --dbglog(fish_num,"fishing_arrang -->config error point_info number  ",i)
            break
        end

        local fish_entify = fish_manager:new_entity()
        if not fish_entify then
            break
        end

        if arrang_id then
            fish_id = point_info[3]
        end

        fish_entify.type = fish_id
        fish_entify.point_offset = {x= point_info[1],y = point_info[2]}
        fish_entify.create_time = curr_msec
        fish_entify.path = fish_path.path_id
        fish_entify.speed = path_time
        fish_entify.rate, fish_entify.threshold = get_fish_rate(fish_id)
        local dis_time = calculate_time(point_info[1],point_info[2],fish_path.path_id,path_time)
        if not dis_time then
            dis_time = path_time + 1
        end

        --print(fish_id,"send_fish: dis_time = ",dis_time,", path_time = ",path_time,", x = ",point_info[1],", y = ",point_info[2])
        fish_entify.duration_time = fish_entify.create_time + dis_time * 1000  --(path_time + 1)* 1000
        local send_fish_info = copy_fish(fish_entify)
        table_insert(fish_list,send_fish_info)

        local score = get_fish_score(fish_id)
        add_fish_count(fish_id,send_fish_info.id,curr_msec,score)
        print(fish_id,"send fish",fish_num,arrang_id)
    end

    --发送鱼信息
    if #fish_list > 0 then
        notify_all('fishing.NTF_REFRESH_FISH',{fish_info = fish_list,})
    end
    
end

local function back_coins(uid,coins)
    local ok,succ,ret = R().basesvr{key=uid}:call('.msg_handler',
        'add_coins',uid,coins,reason.FISHING_BACK_COINS,get_extra_bill_info(uid))
    if not ok then
        errlog(uid,'failed to back_coins',coins,succ)
        return
    end
    if not succ then
        errlog(uid,'failed to back_coins',coins)
        return
    end

    billlog({op="back_coins", uid = uid, curr = ret.curr,r = reason.FISHING_BACK_COINS,change_coins = coins},get_extra_bill_info(uid))
    return ret.curr
end

local function update_scene_gid()
    local now_sec = util.get_now_time()
    --now_sec = math_floor(now_sec / 100)
    scene_gid = string.format( "%d%d%d%d",this_table_gid,self_table_type,scene_id,now_sec)
end

local function get_fish_path(path_type)
    if not global_configs.fishing_path then
        return false
    end

    local path_info = global_configs.fishing_path[path_type]
    if not path_info or #path_info == 0 then
       return false
    end

    return path_info[math_random(1,#path_info)]
end

local function update_person_rate(uid,multiple)
    local tem_rtp = global_configs.fishing_config.fish_rtp
    if not tem_rtp then
        errlog(uid,"rtp is nil")
        tem_rtp = 1.0
    end

    tem_rtp = tem_rtp / 100
    local person_adjust = global_configs.fishing_config.rate_adjust
    if person_adjust then
        local tem_m = 0
        for _,info in pairs(person_adjust) do
            if tem_m > info[1] and multiple > info[1] then
                tem_m = info[1]
                tem_rtp = info[2] or 1
            end
        end
    end

    local player_info = get_player(uid)
    if player_info then
        player_info.rtp_rate = tem_rtp
    end

    R().basesvr{key=uid}:send('.msg_handler','set_person_rate',uid,tem_rtp,get_extra_bill_info(uid))
end

local function bill_scene_adjust()
    local player_coins_map = {}
    local str_date = os.date("%Y%m%d%H%M%S")
    for uid,bill_info in pairs(player_bill) do
        if not is_robot(uid) then
             --写日志
            billlog({op="bill_scene",scene_gid = scene_gid,uid = uid,bullet_count = bill_info.bullet_count,
                bullet_coins = bill_info.bullet_coins,fish_count = bill_info.fish_count,fish_coins = bill_info.fish_coins},get_extra_bill_info(uid))

            --local curr_coins = get_player_curr_coins(uid)

            R().basesvr({key=uid}):send('.msg_handler','add_play_count',uid,1)   

            -- if curr_coins <= constant.POCHAN_COINS then --记录破产日志
            --     billlog({op = "bankrupt_register",uid = uid,game_type = self_game_type,
            --         table_type = self_table_type,
            --         ret = curr_coins,
            --     })
            -- end
        end
        update_person_rate(uid,bill_info.fish_coins / bill_info.bullet_coins)

        local add_score = (bill_info.fish_coins or 0) - (bill_info.bullet_coins or 0)
        player_coins_map[uid] = add_score
    end
    player_bill = {}

    --{"uid":10007606,"left_score":338149,"add_score":10450,"is_robot":true,"pay_fee":550}
end


local function change_scene()
    local scene_style = global_configs.fishing_config.scene_list
    if #scene_style > 0 then 
        scene_id = scene_style[math_random(1,#scene_style)]
        local change_style = math_random(1,3)
        notify_all('fishing.NTF_CHANGE_SCENE',{scene_id = scene_id,style_id = change_style})
--        trigger_event('pause_interval')
    end

    bill_scene_adjust()
end

local function rate_key(table_list)
    local total_weight = 0
    for _,info in pairs(table_list) do
        total_weight =  total_weight + info[2]
    end

    local rate_id
    local rate_rand = math_random(0,total_weight)
    for _,info in pairs(table_list) do
        rate_rand =  rate_rand - info[2]
        if rate_rand <= 0 then
            rate_id = info[1]
            break
        end
    end

    return rate_id
end

local function back_bullet_uid(uid)
    local palyer_bullet_info = bullet_manager[uid]
    if palyer_bullet_info then
        local multiple = 1
        local roomdata = global_configs.roomdata[self_table_type]
        if roomdata.multiple then
            multiple = roomdata.multiple
        end

        local coins = 0
        for index,bullet_info in pairs(palyer_bullet_info) do
            local power_coins = bullet_info.power
            if not power_coins then
                errlog(uid,"change_scene-->back_coins config error",bullet_info.power)
                break
            end

            local new_back_coins = power_coins * multiple
            if new_back_coins > 0 then
                local tem_player_bill = player_bill[uid]
                if not tem_player_bill then
                    return
                end

                tem_player_bill.bullet_count = tem_player_bill.bullet_count - 1
                tem_player_bill.bullet_coins = tem_player_bill.bullet_coins - new_back_coins
                print(uid,"back_bullet_uid--->",tem_player_bill.bullet_count,tem_player_bill.bullet_coins,new_back_coins)
            end

            coins = coins + new_back_coins
        end

        if coins > 0 then
            local curr_icons = back_coins(uid,coins)
            if curr_icons and not is_robot(uid) then
                utils.notify_money_changed(uid,{coins = curr_icons},get_client_fd(uid),reason.FISHING_BACK_COINS)

                -- local uid = uid
                -- local bet_coins = -coins
                -- local produce = 0
                -- local win_lose = 0
                -- local free = 0
                -- expand.sendSummary(self_table_type, uid, bet_coins, produce, win_lose, free)             
            end
        end
    end
end

local function back_bullet()
    local multiple = 1
    local roomdata = global_configs.roomdata[self_table_type]
    if roomdata.multiple then
        multiple = roomdata.multiple
    end
    
    local expend_list = global_configs.fishing_fire
    local back_coins_fun = {}
    for uid, user_bullet in pairs(bullet_manager) do
        local coins = 0
        for index,bullet_info in pairs(user_bullet) do
            local power_coins = expend_list[bullet_info.power]
            if not power_coins then
                errlog(uid,"change_scene-->back_coins config error",bullet_info.power)
                break
            end

            coins = coins + power_coins * multiple
        end

        if coins > 0 then
            table_insert(back_coins_fun,{f = back_coins,id = uid,params = {uid,coins}})
        end
    end

    local ok,results = cocall(#back_coins_fun,back_coins_fun)
    if not ok then
        errlog('failed to cocall',tostring_r(results))
    end

    for uid,ret in pairs(results) do
        if ret then
            if not is_robot(uid) then
                utils.notify_money_changed(uid,{coins = ret},get_client_fd(uid),reason.FISHING_BACK_COINS)          
            end

            local player_info = get_player(uid)
            if player_info then
                player_info.coins = ret
            end
        else
            errlog(uid,'failed to cocall...',ret)
        end
    end

    bullet_manager = {}
    trigger_event("on_update",bullet_manager)
end

--周福利 这里最好交给大厅吧
local function add_player_coins_water(uid,coins)
    local ok,ret = R().basesvr{key=uid}:call('.msg_handler','add_player_coins_water',uid,coins)
    -- if ok and ret then
    --     local seven_reward = global_configs.seven_reward
    --     local goal_list = {}
    --     for k,v in pairs(seven_reward) do  
    --         table_insert(goal_list,(v.coins_low + v.coins_hight)/2)
    --         table_insert(goal_list,coins_hight)
    --     end
    
    --     local function get_section_and_high(value)
    --         local section,section_high
    --         for num,data in pairs(seven_reward) do
    --             if value >= data.coins_low then
    --                 section = num
    --                 section_high = data.coins_hight
    --             end 
    --         end
    
    --         return section,section_high
    --     end
        
    --     for _,value in pairs(goal_list) do
    --         if (ret.pre_coins_water or 0) < value and (ret.curr_coins_water or 0) >= value then
    --             local section,section_high = get_section_and_high(ret.curr_coins_water or 0)
    --             local ntf = {
    --                 today_coins   = ret.curr_coins_water or 0,
    --                 section_count = section,
    --                 section_hight = section_high or 0,
    --                 section_total_count = #seven_reward,
    --             }
    --             send_to_gateway(uid,table_players[uid],'hall.NTF_SEVEN_REWARD_GOAL',ntf)
    --         end
    --     end
    -- end
end

local function clear_fish()
    notify_all('fishing.NTF_Clear_Fish',{})
    fish_manager:clear_all()
end

local function clear_bullet()
    notify_all('fishing.NTF_Clear_Bullet',{})
    back_bullet()
end

local function reset_clear_all()
    
    fish_id_map = {}
    big_fish_count = 0
    medium_fish_count = 0
    small_fish_count = 0

    fish_reduce_count = 0
    fish_add_count = 0
end

local function create_small_fish(curr_msec,fish_id,fish_num)
    local small_fish_list = global_configs.fishing_type.small_fish
    if not small_fish_list then
        errlog("create_small_fish --> small_fish_list is nil")
        return
    end

    local fish_info = small_fish_list[fish_id]
    if not fish_info then
        errlog(fish_id,"config error! can not find fish info")
        return
    end

    if not fish_num then
        fish_num = rate_key(fish_info.rate_num)
    end

    local fish_path = get_fish_path(fish_info.path_type)
    if not fish_path then
        errlog(fish_id,"send_fish not find path",fish_info.path_type,fish_id)
        return
    end

    send_fish(curr_msec,fish_num,fish_path,fish_id)
end

local function create_medium_fish(curr_msec,fish_id,fish_num)
    local medium_fish_list = global_configs.fishing_type.medium_fish
    if not medium_fish_list then
        errlog("create_medium_fish --> medium_fish_list is nil")
        return
    end

    local fish_info = medium_fish_list[fish_id]
    if not fish_info then
        errlog(fish_id,"config error! can not find fish info")
        return
    end

    if not fish_num then
        fish_num = rate_key(fish_info.rate_num)
    end

    local fish_path = get_fish_path(fish_info.path_type)
    if not fish_path then
        errlog(fish_id,"send_fish not find path",fish_info.path_type,fish_id)
        return
    end

    send_fish(curr_msec,fish_num,fish_path,fish_id)
end

local function create_big_fish(curr_msec,fish_id,fish_num)
    local big_fish_list = global_configs.fishing_type.big_fish
    if not big_fish_list then
        errlog("create_big_fish --> big_fish_list is nil")
        return
    end

    local fish_info = big_fish_list[fish_id]
    if not fish_info then
        errlog(fish_id,"config error! can not find fish info")
        return
    end

    if not fish_num then
        fish_num = rate_key(fish_info.rate_num)
    end

    local fish_path = get_fish_path(fish_info.path_type)
    if not fish_path then
        errlog(fish_id,"send_fish not find path",fish_info.path_type,fish_id)
        return
    end

    send_fish(curr_msec,fish_num,fish_path,fish_id)
end

local function create_special_fish(fish_id,curr_msec)
    if not global_configs.fishing_type.special_boss then
        errlog(fish_id,"create_special_fish error! config error")
        return
    end
    local fish_info = global_configs.fishing_type.special_boss[fish_id]
    if not fish_info then
        errlog(fish_id,"create_special_fish not find fish_info")
        return
    end

    local fish_path = get_fish_path(fish_info.path_type)
    if not fish_path then
        errlog(fish_id,"create_special_fish not find path",fish_info.path_type)
        return
    end

    local speed = 1.0
    if fish_path.path_speed and fish_path.path_speed > 0 then
        speed = fish_path.path_speed
    end

    local path_time = fish_path.path_time / speed
    local fish_entify = fish_manager:new_entity()
    if fish_entify then
        fish_entify.type = fish_id
        fish_entify.create_time = curr_msec
        fish_entify.path = fish_path.path_id
        fish_entify.speed = path_time
        fish_entify.duration_time = curr_msec + path_time * 1000
        fish_entify.rate, fish_entify.threshold = get_fish_rate(fish_id)
        local send_fish = copy_fish(fish_entify)
        notify_all('fishing.NTF_REFRESH_BOSS',{fish_info = send_fish,description = fish_info.appear_desc})

        trigger_event('add_lock_fish',send_fish.id,curr_msec,fish_info.score or 0)
    end

    send_fish(curr_msec,1,fish_path,fish_id)
end

local function create_fishboom(curr_msec)
    local fish_boom = global_configs.fishing_multiple.fish_boom
    if not fish_boom then
        errlog("create_fishboom not find fish_boom")
        return
    end

    local fish_info = fish_boom[math_random(1,#fish_boom)]
    local fish_path = get_fish_path(fish_info.path_type)
    if not fish_path then
        errlog("create_fishboom not find path",fish_info.path_type)
        return
    end

    local arrang_id = fish_info.arrang_id
    local fish_num
    if arrang_id then
        local arr_info = global_configs.fishing_arrang[arrang_id]
        if arr_info then
            fish_num = #arr_info.point
        end
    end

    if not fish_num then
        fish_num = 1
    end

    notify_all('fishing.NTF_Message_Hint',{status = 1,msg = fish_info.appear_desc})
    fish_boom_info = {fish_num = fish_num,fish_path= fish_path,arrang_id = arrang_id,time = fish_info.fish_time}
    --errlog("fish_boom status,arrang_id:",arrang_id,", ortime: ",refresh_time,", no_time:",curr_msec)
end

local function create_fish_group(curr_msec)

    if get_total_fish() > global_configs.fishing_config.total_fish_num then
        return
    end

    local fish_group = global_configs.fishing_multiple.fish_group
    if not fish_group then
        errlog("create_fish_group not find fish_group")
        return
    end

    local fish_info = fish_group[math_random(1,#fish_group)]
    local fish_path = get_fish_path(fish_info.path_type)
    if not fish_path then
        errlog("create_fish_group not find path",fish_info.path_type)
        return
    end

    local arrang_id = fish_info.arrang_id
    local fish_num
    if arrang_id then
        local arr_info = global_configs.fishing_arrang[arrang_id]
        if arr_info then
            fish_num = #arr_info.point
        end
    end

    if not fish_num then
        fish_num = 1
    end

    --print(arrang_id,"create_fish_group-->",fish_num)
    send_fish(curr_msec,fish_num,fish_path,0,arrang_id)
end

local function send_fishboom(curr_msec)
    send_fish(curr_msec,fish_boom_info.fish_num,fish_boom_info.fish_path,0,fish_boom_info.arrang_id)
    refresh_time = curr_msec + fish_boom_info.time * 1000
    --errlog("send_fishboom",curr_msec,", no_time:",fish_boom_info.time)
end

local function fishboom_manager(curr_msec)
    if curr_game_status == GAME_STATUS_BOOM then
        if get_total_fish() < 5 or refresh_time < curr_msec then
            trigger_event('open_close_lock',true)
            refresh_boom_delay = false
            refresh_fish_boom = true
            curr_game_status = GAME_STATUS_NORMAL
            refresh_time = curr_msec
        end
    elseif curr_game_status == GAME_STATUS_BOOM_SEND then
        --鱼潮来了 关闭机器人的锁定鱼吧，不然客户端显示 有问题
        trigger_event('open_close_lock',false)
        send_fishboom(curr_msec)
        curr_game_status = GAME_STATUS_BOOM
    elseif curr_game_status == GAME_STATUS_BOOM_MSGHINT then
        curr_game_status = GAME_STATUS_BOOM_SEND
        clear_fish()
        create_fishboom(curr_msec)
        delay_time_sec(curr_msec,2)
    elseif curr_game_status == GAME_STATUS_NORMAL then
        local scene_style = global_configs.fishing_config.scene_list
        if #scene_style > 0 then 
            scene_id = scene_style[math_random(1,#scene_style)]
            local change_style = math_random(1,3)
            notify_all('fishing.NTF_CHANGE_SCENE',{scene_id = scene_id,style_id = change_style})
            trigger_event('pause_interval')
            dbglog("NTF_CHANGE_SCENE")
        end
        reset_clear_all()
        delay_time_sec(curr_msec,2)
        curr_game_status = GAME_STATUS_BOOM_MSGHINT
    end
end


local function dissmiss_table()
    local uids = {}
    local robots = {}
    for uid,player_info in pairs(player_info_list) do
        local game_session = table_players[uid]
        local robot = is_robot(uid)
        if not robot then 
            --返还没碰撞的金币
            local ok,ret = xpcall(back_bullet_uid,debug.traceback,uid)
            if not ok then
                errlog(ret)
            end            
        end

        leave(uid)

        local roomdata = global_configs.roomdata[self_table_type]
        if robot and roomdata and roomdata.robot_type then
            table_insert(robots,{type=roomdata.robot_type, uid=uid, coins=player_info.coins})
        end
        
        table_insert(uids,uid)
    end

    notify_matchsvr_table_stats(true)                                       --更新桌子
    skynet.send('.table_mgr','lua','on_table_delete',self_table_id,uids)    --删除状态
    --R().robotmgr(1):send('.msg_handler','put_back_robots',robots)           --归还机器人
    --put_back_robot(robots)
    --put_back_robots()
    return true
end

--检查是否关闭桌子
local function check_close_table(curr_time)
    if stopping_server then        
        billlog({op = "stop_table",status = curr_status,password = self_password})
        closing_server = true --直接关闭桌子
    end

    if not closing_server then
        if curr_time - game_time <= 30 then --桌子刚启动30秒内不关桌
            return
        end
    end

    if not have_player() then --没有真人 就关闭桌子吧
        closing_server = true
        print("-----Non-existent person will close table----",self_game_type,self_table_id)
    end

    if closing_server == true then
        local ok,ret = xpcall(dissmiss_table,debug.traceback)
        if not ok then
            errlog(ret)
        end
        
        billlog({op = "close_table",password = self_password})
        dbglog('now delete this table',self_table_id)
        skynet.exit()
    end
end


local function changescene_manager(curr_msec)
    if curr_game_status == GAME_STATUS_NORMAL then
        fish_boom_info = {}
        mermaid_sended_status   = MERMAID_BOSS_STATUS_NOR
        mermaid_sended_first    = false
        devilfish_sended       = false
        refresh_fish_boom      = false
        --先把鱼清理了
        fish_manager:clear_all()

        change_scene()
        update_scene_gid()
        reset_clear_all()
        delay_time_sec(curr_msec,CHANGE_SCENE_TIME)
        check_close_table(math_floor(curr_msec/1000))
        curr_game_status = GAME_STATUS_SCENE
    else
        scene_time = 0
        curr_game_status = GAME_STATUS_NORMAL
        --clear_fish()
        notify_all('fishing.NTF_Clear_Fish',{})
    end
end

local function refresh_fish(curr_msec,fish_id)
    --local fish_type = math_floor(fish_id / 1000)
    local fish_type = math.floor(string.reverse(fish_id) % 10)
    if FISH_TYPE_SMALL == fish_type then
        if small_fish_count < global_configs.fishing_config.small_fish_min then
            create_small_fish(curr_msec,fish_id)
        end
    elseif FISH_TYPE_MUDIUM == fish_type then
        if medium_fish_count < global_configs.fishing_config.medium_fish_min then
            create_medium_fish(curr_msec,fish_id)
            last_senior_fish_time = curr_msec +  SENIOR_REFRESH_INTERVAL * 1000
        end
    elseif FISH_TYPE_BIG == fish_type then
        if big_fish_count < global_configs.fishing_config.big_fish_min then
            create_big_fish(curr_msec,fish_id)
            last_senior_fish_time = curr_msec +  SENIOR_REFRESH_INTERVAL * 1000
        end
    end
end

local function parse_fish(curr_msec,scene_time)

    if refresh_time > curr_msec then
        return
    end

    local fish_roomdata = global_configs.fishing_room[self_table_type]
    if not fish_roomdata then
        errlog(self_table_type,"config error! can not find fish_roomdata")
        return
    end

    local player_num = get_player_num()
    if not player_num or player_num == 0 then
        player_num = 1
    end

    local refresh_data = fish_roomdata[player_num]
    if not refresh_data then
        errlog(self_table_type,"config error! can not find refresh_data",player_num)
        return 
    end

    if not refresh_data.rate or not refresh_data.rate.tpye then
        errlog(self_table_type,"config error! rate or tpye is nil",player_num)
        return
    end

    local type_id = rate_key(refresh_data.rate.tpye)
    if not type_id then
        errlog(self_table_type,"config error! type_id is nil",player_num)
        return
    end
    
    --特殊处理-->鱼潮前段时间 只刷小鱼
    local fish_special_time = global_configs.fishing_config.advance_time or 15
    if (scene_time < FISH_BOOM_TIME and scene_time > FISH_BOOM_TIME - fish_special_time) or refresh_boom_delay then
--        dbglog(self_table_type,"fish_boom will come!now only refresh FISH_TYPE_SMALL",type_id)
        type_id = FISH_TYPE_SMALL
    end

    --高级鱼刷新间隔
    if type_id == FISH_TYPE_MUDIUM or type_id == FISH_TYPE_BIG then
        if last_senior_fish_time > curr_msec then
            --dbglog(type_id,"last_senior_fish_time",last_senior_fish_time,curr_msec)
            --间隔时间刷小鱼
            type_id = FISH_TYPE_SMALL
        end
    end

    if not refresh_data.rate[type_id] then
        errlog(self_table_type,"config error! type_info is nil",type_id)
        return
    end

    --local fish_id = rate_key(refresh_data.rate[type_id])
    local fish_list = refresh_data.rate[type_id]
    local index = math_random(1,#fish_list)
    local fish_id = fish_list[index]
    if not fish_id then
        errlog(self_table_type,"config error! fish_id is nil",type_id)
        return
    end
    
    --print(type_id,"parse_fish",fish_id,#fish_list,index)
    refresh_fish(curr_msec,fish_id)
    refresh_time = curr_msec + rate_key(refresh_data.frequency)
    
    if refresh_group_time < curr_msec then
        create_fish_group(curr_msec)
        refresh_group_time = curr_msec + math_random(5,10) * 1000
    end
end

function distribute_fish(curr_msec)
    if last_time < curr_msec then
        scene_time = scene_time + (curr_msec - last_time) / 1000
        last_time = curr_msec
    else
        errlog("time error---> last_time >= curr_time")
        return
    end
    
    if wait_status_time > curr_msec then
        errlog("wait_status_time",wait_status_time,curr_msec)
        return
    end

    -- debug
    if scene_time > global_configs.fishing_config.scene_time + 20 then
        errlog(self_table_type,"scene_time to big",scene_time,global_configs.fishing_config.scene_time,curr_game_status)
    end

    if scene_time > 120 and scene_time < 125 and not mermaid_sended_first then
        --2分钟刷新金龙鱼
        if mermaid_sended_status == MERMAID_BOSS_STATUS_NOR then
            mermaid_sended_status = MERMAID_BOSS_STATUS_NTF
            if not global_configs.fishing_type.special_boss then
                errlog("create_special_fish error! config error",FISH_SEPCIAL_MERMAID)
                mermaid_sended_first = true
                return
            end
            local fish_info = global_configs.fishing_type.special_boss[FISH_SEPCIAL_MERMAID]
            if not fish_info then
                errlog(FISH_SEPCIAL_MERMAID,"create_special_fish not find fish_info")
                mermaid_sended_first = true
                return
            end

            boss_delay_time = curr_msec + 3*1000
            notify_all('fishing.NTF_Message_Hint',{status = 2,msg = fish_info.appear_desc})
        elseif boss_delay_time < curr_msec and  mermaid_sended_status == MERMAID_BOSS_STATUS_NTF then
            mermaid_sended_status = MERMAID_BOSS_STATUS_NOR
            create_special_fish(FISH_SEPCIAL_MERMAID,curr_msec)
            mermaid_sended_first = true
        end
        
    elseif (scene_time > FISH_BOOM_TIME and not refresh_fish_boom and scene_time < global_configs.fishing_config.scene_time) or refresh_boom_delay then
        --如果 场景中 还存在大鱼 中鱼  就延时 刷新鱼潮
        if not refresh_boom_delay and (big_fish_count > 0 or medium_fish_count > 0) and curr_game_status == GAME_STATUS_NORMAL then
            refresh_boom_delay = true
            dbglog(scene_time,"refresh_boom_delay is true,big_fish_count:",big_fish_count,"medium_fish_count:",medium_fish_count)
            return
        elseif big_fish_count == 0 and medium_fish_count == 0 and curr_game_status == GAME_STATUS_NORMAL then
            fishboom_manager(curr_msec)
        elseif refresh_boom_delay and curr_game_status == GAME_STATUS_NORMAL then
            --刷点鱼吧（这里只会刷小鱼）
            parse_fish(curr_msec,scene_time)
--            dbglog(scene_time,"refresh_boom_delay is true,big_fish_count:",big_fish_count,"medium_fish_count:",medium_fish_count)
        end
        
        if curr_game_status ~= GAME_STATUS_NORMAL then
            fishboom_manager(curr_msec)
        end
        
    elseif scene_time < global_configs.fishing_config.scene_time then
        --常规刷鱼 大 中 小
        parse_fish(curr_msec,scene_time)
    else
        changescene_manager(curr_msec)
    end
end

function duration_fish(curr_msec)

    -- if curr_game_status == GAME_STATUS_BOOM then
    --     -- 鱼潮不做有效时间判断
    --     return
    -- end

    local remove_list = {}
    local remove_map = {}
    fish_map_count = 0
    for fish_id,_ in pairs(fish_id_map) do
        local fish_entity = get_fish_entity(fish_id)
        if not fish_entity then
            table_insert(remove_list,fish_id)
        elseif fish_entity.index_id ~= constant.INVALID_ID and fish_entity.duration_time < curr_msec then
            table_insert(remove_list,fish_id)
        elseif fish_entity.index_id == constant.INVALID_ID then
            table_insert(remove_map,fish_id)
        end

        fish_map_count = fish_map_count + 1
    end

    for _,index_id in ipairs(remove_list) do
        remove_fish_id(index_id)
    end

    for _,index_id in ipairs(remove_map) do
        remove_fish_idmap(index_id)
    end
end

local function sync_player_winlose(uid)
    local player_info = get_player(uid)
    if player_info and player_info.winlose  and not is_robot(uid) then
        R().basesvr{key=uid}:send('.msg_handler','sync_winlose',uid,player_info.winlose)
    end
end

local function sync_all_winlose()
    for _,uid in pairs(ordered_players) do
        sync_player_winlose(uid)
    end
end

local function get_personal_rate(uid)
    local player_info = get_player(uid)
    if player_info and not is_robot(uid) then
        local ok,ret = R().basesvr{key=uid}:call('.msg_handler','get_hitrate',uid)
        if ok then
            player_info.personal_rate = ret
        end 
    end
end

local function get_all_rate()
    for _,uid in pairs(ordered_players) do
        get_personal_rate(uid)
    end
end

local function sync(curr_sec,interval)
    if curr_sec ~= time_sync and interval > 0 then
        if curr_sec % interval == 0 then
            time_sync = curr_sec
            return true
        end
    end

    return false
end

local function sync_sec_5(now_sec)
    if sync(now_sec,5) then
        -- 打印游戏状态
        local sysinfo_str = "curr_game_status:"..curr_game_status..", small_fish_count:"..small_fish_count..", medium_fish_count:"..medium_fish_count ..
            ", big_fish_count:"..big_fish_count..", scene_time:"..scene_time..", fish_entity:"..
            fish_manager:get_count()..", player_num:".. get_player_num() ..", table_id:"..this_table_gid..
            ", robot_num:"..robot_num()..", fish_reduce_count:"..fish_reduce_count..", fish_add_count:"..fish_add_count..
            ", fish_id_num:"..fish_map_count.."\n"
        
        for uid,bullet_info in pairs(bullet_manager) do
            local num = #bullet_info
            sysinfo_str = sysinfo_str .. " uid:"..uid ..", bullet_num: ".. num .. ";"
        end

        dbglog(sysinfo_str)

        --- 同步玩家输赢
        sync_all_winlose()

        -- 个人控制
        get_all_rate()

        -- 机器人 金币检查
        --robot_coins_check()
    end
end

local function robot_manage(now_sec)
    if sync(now_sec,10) then
        load_robot()
    end
end

local function send_real_horse_message(uid,coins)
    
    --local message_id = HORSE_MESSAGE_JUNIOR
    local message_id = constant.BROADCAST_IDS.BIDS_BUYU_1
    if self_table_type % 600 == 1 then
        --message_id = HORSE_MESSAGE_MIDDLE
        message_id = constant.BROADCAST_IDS.BIDS_BUYU_2
    elseif self_table_type % 600 == 2 then
        --message_id = HORSE_MESSAGE_SENIOR
        message_id = constant.BROADCAST_IDS.BIDS_BUYU_3
    end

    local roomdata = global_configs.roomdata[self_table_type] or {}
    local exinfo = cjson.encode({game_type = self_game_type})
    local player_info = player_info_list[uid]
    if player_info then
        R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',message_id,
        {name = player_info.name,coin = coins,vip_level = player_info.vip_level})

        R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.GUIDE_BROAD,
        {vip_level = player_info.vip_level,name = player_info.name,game_name = roomdata.name or '',coin =  coins,exinfo = exinfo})
    end  
end

local function check_player_status(now_sec)
    local need_remove = {}
    for uid,player_info in pairs(player_info_list) do
        local client_fd = get_client_fd(uid)
        --print(uid,"check_player_status,fd",client_fd," last_ping_time",player_info.last_ping_time," is_robot",is_robot(uid)," is_enter",player_is_enter[uid])
        if ((client_fd == REGISTER_CLIENT_FD or (not player_is_enter[uid] and not is_robot(uid))) and player_info.last_ping_time and player_info.last_ping_time + 60 < now_sec) or 
            (player_info.last_ping_time and player_info.last_ping_time + 60*60 < now_sec) or 
            not player_info.last_ping_time then

            table_insert(need_remove,uid)
        end
    end

    for _,uid in pairs(need_remove) do
        local ret = leave(uid)
        bullet_manager[uid] = nil
        lock_map[uid] = nil
        player_is_enter[uid] = nil
        person_control_map[uid] = nil
        for index,_uid in pairs(touch_list) do
            if _uid == uid then
                table_remove(touch_list,index)
                break
            end
        end

        dbglog(uid,'check_player_status...error')

        notify_others('fishing.NTF_LEAVE',uid,{uid = uid})
    end
end

local function check_robot_leave(curr_time)
    --金币不足被踢掉
    local roomdata = global_configs.roomdata[self_table_type]
    for uid,player_info in pairs(player_info_list) do
        if is_robot(uid) and robot_manager[uid] and (player_info.coins or 0) < roomdata.min then
            robot_manager[uid]['on_ticked_out'](robot_manager[uid])
        end
    end

    --概率被踢掉
    local robot_type = roomdata.robot_type or -1
    local robot_info = global_configs.robot[robot_type]
    if leave_interval_time <= curr_time and robot_info then
        local interval_time = robot_info.robot_leave.interval_time
        leave_interval_time = curr_time + math_random(interval_time[1], interval_time[2])
        for uid,player_info in pairs(player_info_list) do
            if is_robot(uid) and robot_manager[uid] and math_random(1,100) < (robot_info.robot_leave.rate or 0) then
                robot_manager[uid]['on_ticked_out'](robot_manager[uid])
                break  
            end
        end
    end
end

local function check_player_num_setting(curr_time)
    local roomdata = global_configs.roomdata[self_table_type]
    local robot_type = roomdata.robot_type or -1
    local robot_info = global_configs.robot[robot_type]
    if join_interval_time <= curr_time and robot_info then
        local interval_time = robot_info.robot_join.interval_time
        join_interval_time = curr_time + math_random(interval_time[1], interval_time[2])

        local total_rate  = 0
        local random_rate = math_random(1,100)
        for k,v in pairs(robot_info.robot_join.player_num_setting) do
            total_rate = total_rate + v.rate
            if random_rate < total_rate then
                cur_target_player_num = v.player_num
                break
            end
        end
    end
end

local function init_system_pool_trigger_value()
    --print("init_system_pool_trigger_value=======11",system_pool_trigger)
    local ok,data = R().exdbsvr(1):call('.fishing_mgr','get_fishing_store',self_table_type)
    if not ok or not data then
        return
    end
    local tem_pool = global_configs.fishing_store[self_table_type]
    if not tem_pool then
        return
    end
    
    system_pool_trigger = TRIGGER_STATUS_NORMAL
    --print("init_system_pool_trigger_value=======ccc",tostring_r(data),tostring_r(tem_pool))
    if data.pool_adjust and data.pool_adjust.curr then --调整池大于警报值
 --       print("init_system_pool_trigger_value=======aa",data.pool_adjust.curr,(tem_pool.pool_adjust.base_warn or 0))
        if data.pool_adjust.curr > (tem_pool.pool_adjust.base_warn or 0) then
            if math_random(1,10000) < (tem_pool.pool_adjust.trigger_rate or 0) then
                system_pool_trigger = TRIGGER_STATUS_ADJUST
            end
        end
    end
    
    if data.pool_control and data.pool_control.curr then
--        print("init_system_pool_trigger_value=======bb",data.pool_control.curr,(tem_pool.pool_control.base_warn or 0))
        if data.pool_control.curr <= (tem_pool.pool_control.base_warn or 0) then
            system_pool_trigger = TRIGGER_STATUS_DODGE
        end
    end

   -- print("init_system_pool_trigger_value=======22",system_pool_trigger)
end
----------------------------------------------------------update
function update(now_sec,now_usec)
    local now_msec =(now_sec * 1000) + (now_usec / 1000)
    distribute_fish(now_msec)
    duration_fish(now_msec)
    robot_manage(now_sec)
    sync_sec_5(now_sec)
    check_player_status(now_sec)
    check_robot_leave(now_sec)
    check_player_num_setting(now_sec)
end

local function game_update()
    while true do
        local now_sec,now_usec = util.get_now_time()
        local ok,ret = xpcall(update,debug.traceback,now_sec,now_usec)
        if not ok then 
            errlog(ret)
        end
        skynet.sleep(20)
    end
end
----------------------------------------------------------internal
function internal.start(conf)
    self_table_id = conf.table_id
    self_table_type = conf.table_type
    this_table_gid = conf.table_gid
    self_game_type = conf.game_type
    self_table_pattern = conf.table_conf.table_pattern

    --先填充所有的有座玩家
    for i = 1,get_max_capacity() do
        table_insert(ordered_players,false)
    end

    local now_sec,now_usec = util.get_now_time()
    local scene_style = global_configs.fishing_config.scene_list
    game_time = now_sec
    last_time = (now_sec * 1000) + (now_usec / 1000)
    scene_id = 1
    if #scene_style > 0 then 
        scene_id = scene_style[math_random(1,#scene_style)]
    end
    update_scene_gid()

    local table_conf = conf.table_conf
    print("table_conf================111",tostring_r(table_conf))
    if table_conf and table_conf.robot_num and table_conf.robot_num > 0 then
        print("table_conf================222",tostring_r(table_conf.robot_num))
        load_robot(table_conf.robot_num)
    end
    init_system_pool_trigger_value()

    skynet.fork(game_update)

    return true
end

function internal.stop_server()
    stopping_server = true
end

function internal.close_server()
    closing_server = true
end

function internal.disconnect(uid,game_session)
    if get_client_fd(uid)~= game_session then
        errlog(uid,'invalid status',table_players[uid],game_session)
        return
    end
    --返还没碰撞的金币
    local ok,ret = xpcall(back_bullet_uid,debug.traceback,uid)
    if not ok then
        errlog(ret)
    end

    local ret = leave(uid)
    bullet_manager[uid] = nil
    lock_map[uid] = nil
    player_is_enter[uid] = nil
    person_control_map[uid] = nil
    for index,_uid in pairs(touch_list) do
        if _uid == uid then
            table_remove(touch_list,index)
            break
        end
    end

    sync_player_winlose(uid)

    dbglog(uid,'disconnect...',game_session)

    notify_others('fishing.NTF_LEAVE',uid,{uid = uid})
    return true
end


function internal.enter(uid,game_session,msg)
    local ok,r = on_enter(uid,game_session,msg)
    if not ok then
        send_to_gateway(uid,game_session,'table.RSP_ENTER',{result = r})
        unlock_one_player(uid)
        return false
    end

    send_to_gateway(uid,game_session,'table.RSP_ENTER',r)
    notify_player_enter(uid)

    print(uid,"fishing_enter--->enter",game_session)
    return true
end

function internal.exit()
    skynet.exit()
end

function internal.update_coins_on_table(uid,amount,safe_box)
    local player_info = get_player(uid)
    if player_info then
         player_info.coins = player_info.coins + amount
        local chged_list = {}
        table_insert(chged_list,{uid=uid,coins=player_info.coins})
        if player_info.position then
            notify_all('table.NTF_MONEY_CHANGED',{chged_list=chged_list})
        else
            send_to_gateway(uid,table_players[uid],'table.NTF_MONEY_CHANGED',{chged_list = chged_list})
        end
        if safe_box then
            player_info.safe_box = safe_box
        end
    end
    return true
end

function internal.newmatch_register_all(player_data_list)
    local result = {}
    local failed_list = {}
    local success_list = {}

    local end_idx
    for i,player_data in pairs(player_data_list) do
        local uid = player_data.uid

        if table_players[uid] then
            dbglog(uid,'have been already in table',i)
            table_insert(success_list,uid)
            goto continue
        end

        assert(not player_info_list[uid])
        local player_info = get_player_enter_data(uid)
        if not player_info then
            errlog(uid,'failed to get_player_enter_data')
            table_insert(failed_list,player_data)
            goto continue
        end

        if not lock_one_player(uid,this_table_gid) then
            errlog(uid,'failed to lock_one_player')
            table_insert(failed_list,player_data)
            goto continue
        end

        if get_player_num() >= get_max_capacity() then
            end_idx = i
            unlock_one_player(uid)
            break
        end
        
        local position = find_empty_postion()
        if not position then
            end_idx = i
            unlock_one_player(uid)
            break
        end

        ordered_players[position] = uid
        player_info.position = position
        player_info.last_ping_time = util.get_now_time()
        player_info.init_coins = player_data.coins
        player_info.all_win_lose = 0
        player_info.all_free = 0
        player_info.all_produce = 0
        player_info.all_bet = 0


        add_player(uid,player_info)
        set_client_fd(uid,REGISTER_CLIENT_FD)
        table_insert(success_list,uid)
        print(uid,"newmatch_register_all--------->")
        ::continue::
    end

    if end_idx then
        for i = end_idx,#player_data_list do
            local player_data = player_data_list[i]
            table_insert(failed_list,player_data)
        end
    end

    result.failed_list = failed_list
    result.success_list = success_list
    local table_stats = {}
    table_stats.table_type = self_table_type
    table_stats.left_num = get_max_capacity() - get_player_num()
    table_stats.table_gid = this_table_gid
    table_stats.game_type = self_game_type
    table_stats.table_pattern = self_table_pattern

    result.table_stats = table_stats

    return result
end

function internal.get_player_num()
    return get_player_num()
end

function internal.sync_table_stats()
    local left_num = get_max_capacity() - get_player_num()
    if left_num < 0 then left_num = 0 end

    local table_stats = {}
    table_stats.table_gid = this_table_gid
    table_stats.left_num = left_num
    table_stats.table_pattern = self_table_pattern
    return self_table_type,table_stats
end

function internal.get_game_type()
    return self_game_type,self_table_type
end

function internal.get_user_playing_info()
    local playing_info = {}
    playing_info.game_type = self_game_type
    playing_info.table_type = self_table_type
    playing_info.total = get_player_num()

    return playing_info
end

--计算个人控制
local function cal_personal_control(uid)
    if is_robot(uid) then
        return
    end

    local fish_store = global_configs.fishing_store[self_table_type] or {}
    local tem_control = fish_store.pool_control or {}
    local ok,control_curr = R().exdbsvr(1):call('.fishing_mgr','get_fishing_control',self_table_type)
    if not ok or not control_curr then
        return
    end

    --系统值正常范围内,判断个人控制
    --print("cal_personal_control================",control_curr,tem_control.base_warn)
    if control_curr > (tem_control.base_warn or 0) then
        local gm_warn = (global_configs.gm_control or {}).warn_coins or 50000000
        local catch_status = system_store.get_player_personal_control_result(uid, gm_warn, self_table_type)
        person_control_map[uid] = catch_status ~= 0 and catch_status or person_control_map[uid]
      --  dbglog(uid,"fish tigger personal control-->info data",curr,catch_status,person_control_map[uid])
    end
end

---
local function on_fire(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        dbglog(uid,"on_fire---->player_info is nil")
        return false
    end

    local now_sec,now_usec = util.get_now_time()
    local angle = msg.angle
    local power_id = player_info.curr_power

    local multiple = 1
    local roomdata = global_configs.roomdata[self_table_type]
    if roomdata.multiple then
        multiple = roomdata.multiple
    end

    local power_coins = power_id * multiple
    if power_coins > player_info.coins then
        send_to_gateway(uid,game_session,'fishing.RSP_FIRE',{result = error_code.GOLD_IS_NOT_ENOUGH})
        return false
    end

    local bullet_id = msg.bullet_id
    local user_bullet = bullet_manager[uid]
    if user_bullet and #user_bullet >= global_configs.fishing_config.max_bulllet then
        send_to_gateway(uid,game_session,'fishing.RSP_FIRE',{result = error_code.FISHING_BULLET_IS_MAX})
        errlog(uid,"bullet_manager is max num",bullet_id)
        return false
    end

    if not user_bullet then
        user_bullet = {}
        bullet_manager[uid] = user_bullet
    end

    for index,bullet_info in pairs(user_bullet) do
        if bullet_info.bullet_id == bullet_id then
            errlog(uid,"bullet_id repetition",bullet_id)
            return false
        end
    end

    player_info.coins = player_info.coins - power_coins
    local bullet_speed = global_configs.fishing_config.bullet_speed
    local create_time = (now_sec * 1000) + (now_usec / 1000)
    table_insert(user_bullet,{bullet_id = bullet_id,speed = bullet_speed,angle = angle,power = power_id,
                guns_id = player_info.curr_guns,create_time = create_time})

    send_to_gateway(uid,game_session,'fishing.RSP_FIRE',{curr_coins = player_info.coins,result = error_code.RSP_SUCESS})

    notify_others('fishing.NTF_FIRE',uid,{bullet_info = { id = bullet_id,
        uid = uid,angle = angle, create_time = math_floor(create_time),
        speed = bullet_speed,power = power_id, guns_id = player_info.curr_guns },curr_coins = player_info.coins})
    local str_date = os.date("%Y%m%d%H%M%S")


    if not is_robot(uid) then
        local ret = reduce_coins(uid,power_coins,reason.BET_COIN)
        if not ret then
            errlog(uid,'failed to reduce coins',ok,succ,power_coins)
            --send_to_gateway(uid,game_session,'fishing.RSP_FIRE',{result = error_code.GOLD_IS_NOT_ENOUGH})
            for index,bullet_info in pairs(user_bullet) do
                if bullet_info.bullet_id == bullet_id then
                    errlog(uid,"bullet_id repetition",bullet_id)
                    table_remove(user_bullet,index)
                    break
                end
            end

            return false
        end
        -- sendLoseWinToFriendServer(power_coins)
        -- billlog({ op   = "water_history",  
        --     table_gid  = str_date .. "_" .. self_table_id,
        --     table_type = self_table_type,
        --     uid        = uid,
        --     value      = power_coins,
        --     is_robot   = false,
        --     r          = constant.WATER_TYPE.WATER_BET
        -- })
        -- player_cost_map[uid] = (player_cost_map[uid] or 0) + ret.chged
        -- player_card_record_coins_map[uid] = (player_card_record_coins_map[uid] or 0) - ret.chged

        local curr_coins = ret.curr_coins
        player_info.coins = curr_coins
        utils.notify_money_changed(uid,{coins = curr_coins},game_session,reason.FISHING_FIRE)

        -- player_info.winlose = (player_info.winlose or 0) - power_coins
        -- player_info.all_win_lose = (player_info.all_win_lose or 0) - power_coins
        -- player_info.all_bet = (player_info.all_bet or 0) + power_coins
        -- R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,- power_coins)



    else
        player_cost_map[uid] = (player_cost_map[uid] or 0) + power_coins
        player_card_record_coins_map[uid] = (player_card_record_coins_map[uid] or 0) - power_coins
        player_info.coins = player_info.coins - power_coins
        utils.notify_money_changed(uid,{coins = player_info.coins},game_session,reason.FISHING_FIRE)
        player_info.winlose = (player_info.winlose or 0) - power_coins   


    end

    --机器人 直接返回
    if is_robot(uid) then
        return true
    end

    R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,power_coins)

    if not player_bill[uid] then
        player_bill[uid] = {bullet_count = 0,bullet_coins = 0,fish_count = 0,fish_coins = 0}
    end

    local tem_player_bill = player_bill[uid]
     
    tem_player_bill.bullet_count = tem_player_bill.bullet_count + 1
    tem_player_bill.bullet_coins = tem_player_bill.bullet_coins + power_coins

    -- 非机器人 分配奖池
    local tem_pool = {}
    if global_configs.fishing_store then
        tem_pool = global_configs.fishing_store[self_table_type] or {}
    end

    if not tem_pool.pool_control then
        tem_pool.pool_control = {}
        errlog("fishing_store config error",self_table_type)
    end

    if not tem_pool.pool_adjust then
        tem_pool.pool_adjust = {}
    end

    if not tem_pool.pool_sysback then
        tem_pool.pool_sysback = {}
    end

    local rate_control  = tem_pool.pool_control.fee_rate or 0
    local rate_adjust   = tem_pool.pool_adjust.fee_rate or 0
    local rate_sysback  = tem_pool.pool_sysback.fee_rate or 0

    local control_coins = power_coins * (rate_control / RATE_SCALE)
    local adjust_coins  = power_coins * (rate_adjust / RATE_SCALE)
    local addup_coins   = 0
    local sysback_coins = power_coins * (rate_sysback / RATE_SCALE)

    cal_personal_control(uid)--计算个人控制
    --添加各个奖池数据,受GM控制不加奖池数据
    print("fire====111",uid,control_coins,adjust_coins,person_control_map[uid])
    if not person_control_map[uid] then
         R().exdbsvr(1):send('.fishing_mgr','push_data_pool',self_table_type,control_coins,adjust_coins,addup_coins,sysback_coins)
    end
    --[[
    billlog({op="push_pool",uid=uid,power_coins=power_coins,rate_control = rate_control,rate_adjust = rate_adjust,
        rate_addup  = rate_addup,rate_sysback=rate_sysback,multiple = multiple},get_extra_bill_info(uid))
    ]]

    local fire_interval = get_fire_interval(player_info.curr_guns)
    if player_info.curr_fire_interval ~= fire_interval then
        player_info.curr_fire_interval = fire_interval
         send_to_gateway(uid,game_session,'fishing.NTF_UPDATE_FIRE_INTERVAL',{fire_interval = fire_interval/100})
    end 

    return true
end

function internal.fire(uid,game_session,msg)
    return on_fire(uid,msg,game_session)
end

function internal.is_fish_exist(uid,game_session,msg)
    local fish_id = msg.fish_id
    local ret = is_fish_exist(fish_id)

    return ret
end

function internal.on_unreal_lock_fish(uid,game_session,msg)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_use_item---->player_info is nil")
        return false
    end

    local fish_id = msg.fish_id
    local fish_entify = get_fish_entity(fish_id)
    if not fish_entify or fish_entify.index_id == constant.INVALID_ID then
        errlog(uid,"on_unreal_lock_fish index_id is INVALID_ID",fish_id)
        unread_lock_map[uid] = nil
        return false
    end

    unread_lock_map[uid] = fish_id
    notify_others('fishing.NTF_LOCK_FISH',uid,{fish_id = fish_id,uid = uid,real_lock = false})

    return true
end

function internal.on_cancel_unreal_lock_fish(uid,game_session,msg)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_cancel_unreal_lock_fish---->player_info is nil")
        return false
    end

    unread_lock_map[uid] = nil
    notify_others('fishing.NTF_UNLOCK_FISH',uid,{uid = uid})

    return true
end

--在线玩家概况数据
function internal.get_summary_online()
    local res = {}
    for uid, player in pairs(player_info_list) do 
        if not is_robot(uid) then 
            table_insert(res, {
                uid = uid, 
                all_bet = player.all_bet, --总投注
                all_win_lose = player.all_win_lose, --输赢
                all_free = player.all_free, --台费
                all_produce = player.all_win_lose + player.all_bet, --总产出
            })
        end
    end
    return res
end












---------------------------------------------------------handler
function handler.REQ_FIRE(uid,msg,game_session)
    return on_fire(uid,msg,game_session)
end

function handler.REQ_GUNS_LIST(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_change_power---->player_info is nil")
        return false
    end

    local owner_list = {}
    for _,info in pairs(player_info.guns_list) do 
        owner_list[info.id] = true
    end
    
    local guns_list = {}
    for _,guns_info in pairs(global_configs.fishing_guns) do
        local is_have = false

        if owner_list[guns_info.id] or (guns_info.vip_level or 0) == 0 then
            is_have = true
        end

        table_insert(guns_list,{guns_id = tonumber(guns_info.id),is_have = is_have,price = 0,
        validity_time = 0,reman_time = 0})
    end

    print_r(guns_list)
    send_to_gateway(uid,game_session,'fishing.RSP_GUNS_LIST',{guns_list = guns_list,result = error_code.RSP_SUCESS})
    return true
end

function handler.REQ_CHANGE_GUNS(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_change_power---->player_info is nil")
        return false
    end

    local guns_id = tonumber(msg.guns_id)
    local valid_id = false
    if guns_id == player_info.curr_guns then
        errlog(uid,"REQ_CHANGE_GUNS---->curr_guns = guns_id",guns_id)
        return false
    end

    --
    if is_robot(uid) then
        for _,guns_info in pairs(global_configs.fishing_guns) do
            if tonumber(guns_info.id) == guns_id then
                valid_id = true
                break
            end
        end
    else
        local owner_list = {}
        for _,info in pairs(player_info.guns_list) do 
            if info.id ==  guns_id then
                valid_id = true
                break
            end
        end
        
        if not valid_id then
            for _,guns_info in pairs(global_configs.fishing_guns) do
                if tonumber(guns_info.id) == guns_id and (guns_info.vip_level or 0) == 0 then
                    valid_id = true
                    break
                end
            end
        end
    end
    
    if not valid_id then
        errlog(uid,"REQ_CHANGE_GUNS---->guns_id invalid",guns_id)
        send_to_gateway(uid,game_session,'fishing.RSP_CHANGE_GUNS',{result = -100})
        return false
    end

    player_info.curr_guns = guns_id
    local conf = get_curr_guns_info(uid)
    send_to_gateway(uid,game_session,'fishing.RSP_CHANGE_GUNS',{curr_guns = guns_id,fire_interval = conf.fire_interval/100,result = error_code.RSP_SUCESS})
    notify_others('fishing.NTF_CHANGE_GUNS',uid,{uid = uid,guns_id = player_info.curr_guns,fire_interval = conf.fire_interval/100})

    clear_player_rate_info(uid)

    return true
end

function handler.REQ_CHANGE_POWER(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_change_power---->player_info is nil")
        return false
    end

    local curr_index = 0
    local power_status = msg.power_status
    local fishing_list = global_configs.fishing_fire
    for index,power_id in pairs(fishing_list) do       
        if power_id == player_info.curr_power then
            curr_index = index
            break
        end
    end

    local next_index = 0
    if power_status == 1 then --增加威力
        next_index = (curr_index % #fishing_list) + 1
    elseif power_status == 2 then --减少威力
        next_index = (curr_index-1) % #fishing_list
        next_index = next_index == 0 and #fishing_list or next_index
    end

    local curr_power = fishing_list[next_index]
    if not curr_power then
        send_to_gateway(uid,game_session,'fishing.RSP_CHANGE_POWER',{result = error_code.RSP_FAIL})
        return false
    end

    player_info.curr_power = curr_power
    --player_info.curr_guns = get_guns_id(curr_power)
    send_to_gateway(uid,game_session,'fishing.RSP_CHANGE_POWER',{curr_power = curr_power,curr_guns = player_info.curr_guns,result = error_code.RSP_SUCESS})
    notify_others('fishing.NTF_CHANGE_POWER',uid,{power_id = curr_power,uid = uid,curr_guns = player_info.curr_guns})

    clear_player_rate_info(uid)

    return true
end

local function notify_caishenjiadao(uid,coins)
 --   print("=============notify_caishenjiadao",uid,coins)
    local curr_time = util.get_now_time()
    if caishen_end_time[uid] and caishen_end_time[uid] > curr_time then 
        dbglog("have caishen not open")
        return
    end
    local countdown_time = global_configs.caishenjiadao.countdown_time or 10
    local end_time = curr_time + countdown_time + 5
    caishen_coins_map[uid] = coins
    caishen_end_time[uid] = end_time
    send_to_gateway(uid,table_players[uid],'table.NTF_CAISHENJIADAO',
    {end_time = end_time,trigger_coins = coins,game_type = self_game_type})
    billlog({op = "caishenjiadao",type = "trigger",uid = uid,table_type = self_table_type,coins = coins})
end

local function cal_base_store_average_rate(uid,hit_count,fish_rate,fish_store)
    local k1 = fish_store.base_hit.k1 == 0 and 1 or fish_store.base_hit.k1
    local k2 = fish_store.base_hit.k2
    --基础命中率=(1/鱼的倍数)*(1+((命中次数-1）/系数K1))
    local base_rate = (1/fish_rate)*(1+(hit_count-1)/k1)
    local base_rate_limit = (1/fish_rate) * k2 --(1/鱼的倍数)*k2
    base_rate = base_rate >= base_rate_limit and base_rate_limit or base_rate

    --大盘控制系数
    local control_arg = fish_store.pool_control.base_factor or 0

    --个人控制系数
    --print("player_cost_map1111=======",player_cost_map[uid],player_win_map[uid])
    local back_rate = (player_win_map[uid] or 0)/(player_cost_map[uid] or 1)--返水率
    local personal_k = 0 --个人系数
    for k,v in pairs(fish_store.personal_hit) do
        if back_rate >= (v.min or 0) and back_rate <= (v.max or 0) then
            personal_k = v.value or 0
        end
    end
    local personal_rate = 1 + personal_k
    --print("cal_base_store_average_rate111",uid,back_rate,personal_k,personal_rate)


    --起伏波动系数
    local rise_fall_rate = 1 
    local conf_up_rate = (fish_store.rise_fall_hit.up_rate or 0) / 10000 --上升概率
    local conf_down_rate = (fish_store.rise_fall_hit.down_rate or 0) / 10000 --上升概率
    local trigger_add_rate = (fish_store.rise_fall_hit.trigger_add_rate or 0) / 10000 --调整幅度
    local trigger_time_range = fish_store.rise_fall_hit.trigger_time_range
    local continue_time_range = fish_store.rise_fall_hit.continue_time_range
    local up_rate_range = fish_store.rise_fall_hit.up_rate_range
    local down_rate_range = fish_store.rise_fall_hit.down_rate_range

    player_rate_map[uid] = player_rate_map[uid] or {}
    local curr_time = util.get_now_time()
    if curr_time >= (player_rate_map[uid].trigger_time or 0) then
        local random_value = math_random(1,100) / 100
        if random_value <= (player_rate_map[uid].up_rate or conf_up_rate)  then --上升
            player_rate_map[uid].up_rate = (player_rate_map[uid].up_rate or conf_up_rate) - trigger_add_rate
            player_rate_map[uid].is_up = true
        else --下降
            player_rate_map[uid].up_rate = (player_rate_map[uid].up_rate or conf_up_rate) + trigger_add_rate
            player_rate_map[uid].is_up = false
        end
        player_rate_map[uid].trigger_time = curr_time + math_random(trigger_time_range[1],trigger_time_range[2])
        player_rate_map[uid].trigger_continue_time = curr_time + math_random(continue_time_range[1],continue_time_range[2])
    end

    if curr_time <= (player_rate_map[uid].trigger_continue_time or 0) then
        rise_fall_rate = math_random(down_rate_range[1]*100,down_rate_range[2]*100) / 100
        if player_rate_map[uid].is_up then
            rise_fall_rate = math_random(up_rate_range[1]*100,up_rate_range[2]*100) / 100
        end
    end

    --print("uid=rate1=rate2==rate3==rate4==total",uid,base_rate,control_arg,personal_rate,rise_fall_rate,base_rate*control_arg*personal_rate*rise_fall_rate,system_pool_trigger,back_rate,player_rate_map[uid].up_rate or conf_up_rate)

    return base_rate*control_arg*personal_rate*rise_fall_rate,back_rate
end

function handler.REQ_CATCH_FISH(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    --机器人或者掉线的玩家 
    local is_other_player = false
    if msg.uid and msg.uid ~= 0 and uid ~= msg.uid then
        uid = msg.uid
        is_other_player = true
    end

    local player_info = get_player(uid)
    if not player_info then
        dbglog(uid,"on_catch_fish---->player_info is nil",is_other_player)
        print_r(msg)
        return false
    end
    
    local fish_list = msg.fish_id
    local bullet_id = msg.bullet_id 
    local multiple = 1
    local roomdata = global_configs.roomdata[self_table_type]
    if roomdata.multiple then
        multiple = roomdata.multiple
    end

    if not bullet_id then
        errlog(uid,"bullet_id is nill")
        if not is_other_player then
            send_to_gateway(uid,game_session,'fishing.RSP_CATCH_FISH',{result = -100})
        end

        return false
    end

   
    local user_bullet = bullet_manager[uid]
    if not user_bullet then
        errlog(uid,"user_bullet is nill")
        if not is_other_player then
            send_to_gateway(uid,game_session,'fishing.RSP_CATCH_FISH',{result = -100})
        end

        return false
    end

    local index,bullet_entity
    for id,bullet_info in pairs(user_bullet) do
        if bullet_info.bullet_id == bullet_id then
            bullet_entity = bullet_info
            index = id
            break
        end
    end

    if not index then
        errlog(uid,"bullet_entity is nill",bullet_id)
        if not is_other_player then
            send_to_gateway(uid,game_session,'fishing.RSP_CATCH_FISH',{result = -100})
        end

        return false
    end

    --移除子弹
    table_remove(user_bullet,index)

    local success_map = {}
    local win_coins = 0
    local add_jp = 0
    local fish_num = #fish_list
    local power_coins = multiple * bullet_entity.power
    if not is_robot(uid) then
        R().basesvr({key=uid}):send('.msg_handler','add_person_water',uid,power_coins,is_robot(uid))
        local str_date = os.date("%Y%m%d%H%M%S")
        billlog({ op   = "water_history",  
            table_gid  = str_date .. "_" .. self_table_id,
            table_type = self_table_type,
            uid        = uid,
            value      = power_coins,
            is_robot   = false,
            r          = constant.WATER_TYPE.WATER_BET
        })

        sendLoseWinToFriendServer(power_coins)
        player_info.winlose = (player_info.winlose or 0) - power_coins
        player_info.all_win_lose = (player_info.all_win_lose or 0) - power_coins
        player_info.all_bet = (player_info.all_bet or 0) + power_coins
        -- print("___1________feilog______all_win_lose____",uid, player_info.all_win_lose, power_coins)
        -- print("___1________feilog______all_bet____",uid, player_info.all_bet, power_coins)


        player_cost_map[uid] = (player_cost_map[uid] or 0) + power_coins
        --牌局记录
        player_card_record_coins_map[uid] = (player_card_record_coins_map[uid] or 0) - power_coins
        --总输赢
        R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,- power_coins)

    end
    if fish_num == 0 then
        errlog(uid,"fish_num is 00")
        if not is_other_player then 
            send_to_gateway(uid,game_session,'fishing.RSP_CATCH_FISH',{result = -102})
        end

        return false
    end

    local count = 0
    local send_horse_message = false
    local fish_store = global_configs.fishing_store[self_table_type] or {}
    for _,fish_id in ipairs(fish_list) do
        if count > MAX_CATCH_FISH_NUM then
            break
        end

        count = count + 1
        local fish_entify = get_fish_entity(fish_id)--fish_manager:get_entity(fish_id)
        if not fish_entify or fish_entify.index_id == constant.INVALID_ID then
            errlog(uid,"catch_fish index_id is INVALID_ID",fish_id,fish_entify,tostring_r(fish_entify))
            goto continue
        end
        
        local score = get_fish_score(fish_entify.type)  --鱼的积分
        local fish_coins =  score * power_coins
        if person_control_map[uid] then
            if person_control_map[uid] == constant.PERSONAL_STORE_WIN then
                --直接捕中鱼
                win_coins = win_coins + fish_coins
                table_insert(success_map,{fish_id = fish_id,win_coins = fish_coins})
                if power_coins > fish_coins then
                    add_jp = add_jp + power_coins - fish_coins
                end
    
                send_horse_message = score >= HORSE_MESSAGE_SCORE and true or false 

                dbglog(uid,"fish tigger personal control-->catch fish")
                goto continue
            else
                dbglog(uid,"fish tigger personal control--> can not catch fish")
                goto continue
            end
        end
        
        fish_entify.user[uid] = (fish_entify.user[uid] or 0) + power_coins
        fish_entify.hit_map[uid] = (fish_entify.hit_map[uid] or 0) + 1
        
        local average_rate,back = cal_base_store_average_rate(uid,fish_entify.hit_map[uid],score,fish_store)--库存1的命中概率
        average_rate = math_floor(average_rate * 10000) / 10000 --最多保留4位小数
        local rate1 = average_rate
        --print("average_rate==============111",average_rate)
        if not is_robot(uid) then
            if system_pool_trigger == TRIGGER_STATUS_ADJUST then
                --库存2的命中概率=库存1的最终命中率*(1+增加命中率)
                average_rate = average_rate * (1 + (fish_store.pool_adjust.add_rate or 0)/10000)
            elseif system_pool_trigger == TRIGGER_STATUS_DODGE then
                --低于警报值值,库存1的最终命中率=基础命中率*大盘控制系数*个人命中系数*起伏波动系数* 0.5(可配置)
                average_rate = average_rate * (fish_store.pool_control.warn_factor or 0)
            end
        else --机器人命中率= 真人的最终控制率 * 机器人系数
            local roomdata = global_configs.roomdata[self_table_type]
            if roomdata and roomdata.robot_type then
                local robot_type = roomdata.robot_type 
                local robot_info = global_configs.robot[robot_type] or {}
                average_rate = average_rate * (robot_info.hit_arg or 0)
            end
        end
       -- print("uid=rate1=rate2==rate3==rate4==total",uid,rate1,average_rate,system_pool_trigger,back)

      --  print("average_rate==============222",average_rate)
        if math_random(1,100) < (average_rate * 100) then
            win_coins = win_coins + fish_coins
            table_insert(success_map,{fish_id = fish_id,win_coins = fish_coins})
            if power_coins > fish_coins then --加入个人奖金池
                add_jp = add_jp + power_coins - fish_coins
            end

            send_horse_message = score >= HORSE_MESSAGE_SCORE and true or false
        end

        ::continue::
    end
    
    -- if not is_robot(uid) then
    --     cal_personal_control(uid)--计算个人控制
    --  --   print("person_control===========",uid,person_control_map[uid])
    -- end

    if #success_map > 0 then
        local ntf_info = {uid = uid,win_coins = win_coins,fish = success_map}
        notify_all('fishing.NTF_CATCH_FISH',ntf_info)
        for _,info in pairs(success_map) do
            remove_fish_id(info.fish_id)
        end

        --机器人金钱修改不走redis
        if not is_robot(uid) then

            sendLoseWinToFriendServer(0 - win_coins)
            player_win_map[uid] = (player_win_map[uid] or 0) + win_coins
            player_card_record_coins_map[uid] = (player_card_record_coins_map[uid] or 0) + win_coins

            player_info.winlose = player_info.winlose + win_coins
            player_info.all_win_lose = player_info.all_win_lose + win_coins
            -- print("___2________feilog______all_win_lose____",uid, player_info.all_win_lose, win_coins)

            local ret = add_coins(uid,win_coins,reason.WIN_COIN) --注意call会使协程挂起
            if not ret then
                errlog(uid,'failed to add_coins',win_coins)
            end
            R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,win_coins)

            local curr_coins = ret.curr_coins
            player_info.coins = curr_coins
            notify_all('fishing.NTF_COINS_CHANGE',{uid = uid,curr_coins = curr_coins})
        else
            player_win_map[uid] = (player_win_map[uid] or 0) + win_coins
            player_card_record_coins_map[uid] = (player_card_record_coins_map[uid] or 0) + win_coins

            player_info.coins = player_info.coins + win_coins
            notify_all('fishing.NTF_COINS_CHANGE',{uid = uid,curr_coins = player_info.coins})          
        end
        --检查是否触发财神驾到
        if not is_robot(uid) then
            local vip_level = player_info.vip_level
         --   print("===========",uid,win_coins,self_table_type,vip_level or 0)
            if system_store.check_trigger_caishenjiadao(uid,win_coins,self_table_type,vip_level or 0) then
                notify_caishenjiadao(uid,win_coins)
            end
        end
        --添加玩家首冲进度
        -- R().activitysvr(1):send('.activity_mgr','act_add_first_charge_process',uid,win_coins)

        if not is_other_player then
            utils.notify_money_changed(uid,{coins = curr_coins},game_session,reason.FISHING_CATCH)
        end
        -- if not is_robot(uid) then
        --     player_info.winlose = player_info.winlose + win_coins
        --     player_info.all_win_lose = player_info.all_win_lose + win_coins
        --     R().basesvr({key=uid}):send('.msg_handler','add_total_coins',uid,win_coins)
        -- end
        if not player_bill[uid] then
            player_bill[uid] = {bullet_count = 0,bullet_coins = 0,fish_count = 0,fish_coins = 0}
        end
    
        local tem_player_bill = player_bill[uid]
        tem_player_bill.fish_count = tem_player_bill.fish_count + #success_map
        tem_player_bill.fish_coins = tem_player_bill.fish_coins + win_coins
        
        if not is_robot(uid) then
            --加入个人奖池
            if add_jp > 0 then
                R().basesvr{key=uid}:send('.msg_handler','add_jackpots',uid,self_table_type,add_jp,get_extra_bill_info(uid))
            end

            R().basesvr{key=uid}:send('.msg_handler','sub_lose_coins',uid,win_coins)

            --个人控制
            gm_store_coins_add = 0
            if person_control_map[uid] then
                local personal_status = person_control_map[uid]
                if personal_status == constant.PERSONAL_STORE_WIN then
                    R().basesvr({key=uid}):send('.msg_handler','reduce_curr_control_data',uid,win_coins,self_game_type)
                    --R().exdbsvr(1):send('.gm_coins_mgr','reduce_gm_coins',win_coins,{uid = uid,table_type = self_table_type})
           --         print("reduce_gm_coins===========111",win_coins)
                    gm_store_coins_add = win_coins
                end
                person_control_map[uid] = nil
            end

            local fish_store = global_configs.fishing_store[self_table_type] or {}
            local tem_control = fish_store.pool_control or {}
            local tem_adjust = fish_store.pool_adjust or {}

            --调控奖池
         --   print("real_win_coins============",win_coins,gm_store_coins_add,system_pool_trigger,person_control_map[uid])
            local real_win_coins = win_coins - gm_store_coins_add --去掉GM库存部分
            if system_pool_trigger == TRIGGER_STATUS_ADJUST then
                R().exdbsvr(1):send('.fishing_mgr','adjust_pool_handle',self_table_type,real_win_coins)
            else
                R().exdbsvr(1):send('.fishing_mgr','control_pool_handle',self_table_type,real_win_coins)
            end
            
            init_system_pool_trigger_value() --重新计算触发库存情况
            add_player_coins_water(uid,win_coins) --周福利通知
        end

        if send_horse_message then
            send_real_horse_message(uid,win_coins)
        end

        trigger_event('update_status',uid,player_info.coins,bullet_manager)
    else
        --未捕到鱼
        if person_control_map[uid] then
            if person_control_map[uid] == constant.PERSONAL_STORE_LOSE then
                R().basesvr({key=uid}):send('.msg_handler','add_curr_control_data',uid,power_coins,self_game_type)
                --R().exdbsvr(1):send('.gm_coins_mgr','add_gm_coins',power_coins,false,{uid=uid,table_type=self_table_type})
         --       print("add_gm_coins===========333",power_coins)
            else --控制赢没打中 算进库存1
                R().exdbsvr(1):send('.fishing_mgr','add_fishing_control',self_table_type,power_coins)
            end
            
            person_control_map[uid] = nil
        end

        if not is_robot(uid) then
            init_system_pool_trigger_value() --重新计算触发库存情况
            -- realTimeWinLose(uid)
        end
    end

    --若当前子弹判定之后,库存1的值大于上限值,将多出的部分移到库存2
    --print("is_robot===111")
    if not is_robot(uid) then
        cal_personal_control(uid)--计算个人控制
        local ok,control_curr = R().exdbsvr(1):call('.fishing_mgr','get_fishing_control',self_table_type)
        local control_coins_limit = fish_store.pool_control.base_warn_max or 10000000
        --print("is_robot===333",control_curr,control_coins_limit)
        if control_curr and control_curr >= control_coins_limit then
            local extra = control_curr - control_coins_limit
      --      print("fire====222",uid,control_curr,extra)
            R().exdbsvr(1):send('.fishing_mgr','sub_fishing_control',self_table_type,extra)
            R().exdbsvr(1):send('.fishing_mgr','add_fishing_adjust',self_table_type,extra)
        end

        -- --捕鱼流水不算机器人
        -- R().basesvr({key=uid}):send('.msg_handler','add_person_water',uid,power_coins,is_robot(uid)) 
    end
    
   
       
    return true
end

function handler.REQ_LOCK_FISH(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_use_item---->player_info is nil")
        return false
    end

    -- if lock_map[uid] then
    --     send_to_gateway(uid,game_session,'fishing.RSP_LOCK_FISH',{result = -100})
    --     return false
    -- end

    local fish_id = msg.fish_id
    local fish_entify = get_fish_entity(fish_id)
    if not fish_entify or fish_entify.index_id == constant.INVALID_ID then
        errlog(uid,"REQ_LOCK_FISH index_id is INVALID_ID",fish_id)
        send_to_gateway(uid,game_session,'fishing.RSP_LOCK_FISH',{result = -100})
        lock_map[uid] = nil
        return false
    end

    lock_map[uid] = fish_id
    send_to_gateway(uid,game_session,'fishing.RSP_LOCK_FISH',{result = error_code.RSP_SUCESS})
    notify_others('fishing.NTF_LOCK_FISH',uid,{fish_id = fish_id,uid = uid,real_lock = true})
    return true
end

function handler.REQ_UNLOCK_FISH(uid,msg,game_session)
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid uid',get_client_fd(uid),game_session)
        return false
    end

    local player_info = get_player(uid)
    if not player_info then
        errlog(uid,"on_use_item---->player_info is nil")
        return false
    end

    if not lock_map[uid] then
        send_to_gateway(uid,game_session,'fishing.RSP_UNLOCK_FISH',{result = -100})
        return false
    end

    lock_map[uid] = nil
    send_to_gateway(uid,game_session,'fishing.RSP_UNLOCK_FISH',{result = error_code.RSP_SUCESS})
    notify_others('fishing.NTF_UNLOCK_FISH',uid,{uid = uid})
    return true
end

function handler.REQ_LEAVE(uid,msg,game_session)

    --返还没碰撞的金币
    local ok,ret = xpcall(back_bullet_uid,debug.traceback,uid)
    if not ok then
        errlog(ret)
    end

    bullet_manager[uid] = nil
    lock_map[uid] = nil
    player_is_enter[uid] = nil
    person_control_map[uid] = nil
    local player_info = player_info_list[uid]

    local ret = leave(uid)

    send_to_gateway(uid,game_session,'fishing.RSP_LEAVE',{result = error_code.RSP_SUCESS})
    notify_others('fishing.NTF_LEAVE',uid,{uid = uid})
    
    for index,_uid in pairs(touch_list) do
        if _uid == uid then
            table_remove(touch_list,index)
            break
        end
    end

    if not is_robot(uid) and player_info then
        local init_coins = player_info.init_coins or 0
        print("check_lucky_tigger",init_coins)
        R().hallsvr({key=uid}):send('.msg_handler', 'check_lucky_tigger',uid,self_game_type,init_coins)
    end
    sync_player_winlose(uid)
    return true
end

function handler.REQ_CHAT(uid,msg,game_session)

    local player_info = get_player(uid)
    local curr_time = util.get_now_time()
    if player_info.last_chat_time and curr_time - player_info.last_chat_time < 1 then
        send_to_gateway(uid,game_session,'table.RSP_CHAT', {result = error_code.REQ_CHAT_TOO_FAST})
        return false
    end

    player_info.last_chat_time = curr_time

    send_to_gateway(uid,game_session,'table.RSP_CHAT',{result = error_code.RSP_SUCESS})

    local ntf = {
        uid = uid,
        type = msg.type,
        picture_id = msg.picture_id,
        content = msg.content,
        voice = msg.voice,
        content_id = msg.content_id,
        name = player_info.name,
        icon = player_info.icon,
        sex = player_info.sex,
    }

    notify_all('table.NTF_CHAT',ntf)

    return true
end

--换游戏
-- function handler.REQ_GAME_CHANGE(uid,msg,game_session)
--     local roomdata_list = global_configs.roomdata or {}
--     local roomdata = roomdata_list[msg.table_type]
--     if not roomdata then
--         errlog(self_table_type,"check_game_change_table but roomdata is nil")
--         return false
--     end

--     local player_info = player_info_list[uid]
--     if not player_info then
--         dbglog("REQ_GAME_CHANGE error player_info is nil",uid)
--         send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.PERMISSION_DENIDE})
--         return false
--     end

--     if player_info.coins < (roomdata.min or 0) then
--         send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.GOLD_IS_NOT_ENOUGH})
--         return false
--     end

--     if (roomdata.max or 0) ~= 0 and player_info.coin > (roomdata.max or 0) then
--         send_to_gateway(uid,game_session,'table.RSP_GAME_CHANGE',{result = error_code.GOLD_OUT_OF_MAX})
--         return false
--     end

--     print("change_table_type=============",msg.table_type)

--     leave(uid) --离开游戏

--     local user_data = {
--         uid = uid,
--         table_type = msg.table_type,
--         begin_time = util.get_now_time(),
--         name = player_info.name,
--         coins = player_info.coins,
--         sex = player_info.sex,
--         icon = player_info.icon,
--         --old_table_gid = self_table_gid,
--         --ip_limit = false,
--         --login_ip = player_info.login_ip,
--     }   

--     --请求匹配服进行匹配了
--     local ok = R().newmatchsvr(1):call(".table_mgr", "match_player",user_data)
--     if not ok then
--         errlog(string_format("uid(%d) call newmatchsvr table_mgr match_player error",uid))
--         send_to_gateway(uid, game_session, "table.RSP_GAME_CHANGE", { result = error_code.RSP_FAIL })
--         return true
--     end
--     send_to_gateway(uid, game_session, "table.RSP_GAME_CHANGE", { result = error_code.RSP_SUCESS })

--     return true
-- end

local function update_player_coins(uid, coins)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = coins
    else
        errlog("player info not exist=====",uid,coins)
    end
end

local function check_have_enough_coins(uid,coins)
    local player_info = player_info_list[uid]
    if not player_info or player_info.coins < coins then
        return false
    end
    return true
end

local function caishen_coins(uid, coins, award_coins, ...)
    local robot = is_robot(uid)
    local ok, succ, ret = R().basesvr({ key = uid }):call(".msg_handler", "caishen_coins", uid, coins, award_coins, {is_robot=robot},get_extra_bill_info(uid))
    if not ok then
        errlog(string_format("uid(%d) call basesvr caishen_coins coins error", uid))
        return false
    end
    if not succ then
        errlog(string_format("uid(%d) basesvr caishen_coins coins succ == false error", uid))
        return false
    end

    --update_player_coins(uid, ret.curr)
    return ret
end

local function pay_caishen_coins(uid,coins)
    local caishenjiadao_store = global_configs.caishenjiadao_store
    local fee_rate = caishenjiadao_store.fee_rate
    local sysback_coins = math_floor((coins *fee_rate) / 10000)
    local base_coins = coins - sysback_coins
    local curr_coins
    local ret_coins = system_store.check_caishen_store_result(self_table_type,uid,coins)
    local player_info = player_info_list[uid]
    player_info.all_bet = player_info.all_bet + coins
    -- local produce = 0
    local win_lose = 0   
    if ret_coins then
        print("add coins",ret_coins)
        player_info.all_win_lose = player_info.all_win_lose - coins + ret_coins
        sendLoseWinToFriendServer(coins - ret_coins) 
               
        curr_coins = caishen_coins(uid,coins,ret_coins)
        if not curr_coins then
            errlog("reduce coins failed",ret )
            return error_code.NOT_ENOUGH_COINS
        end
        --改变财神库存
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self_table_type,uid,base_coins,sysback_coins)
        R().exdbsvr(1):send('.caishen_mgr','sub_caishen_base',self_table_type,uid,ret_coins)
    else
        player_info.all_win_lose = player_info.all_win_lose - coins        
        sendLoseWinToFriendServer(coins)         
        local ret = reduce_coins(uid, coins, reason.OPEN_CAISHEN)
        if not ret then
            errlog("reduce coins failed",ret )
            return error_code.NOT_ENOUGH_COINS
        end
        --改变财神库存
        R().exdbsvr(1):send('.caishen_mgr','push_data_pool',self_table_type,uid,base_coins,sysback_coins)
        curr_coins = ret.curr_coins
    end

    utils.notify_money_changed(uid,{coins = curr_coins})
    notify_all("table.NTF_MONEY_CHANGED", { chged_list = { { uid = uid, coins = curr_coins } } })
    
    update_player_coins(uid, curr_coins)
    caishen_coins_map[uid] = nil
    caishen_end_time[uid] = nil 
    return error_code.RSP_SUCESS,ret_coins    
end

function handler.REQ_OPEN_CAISHEN(uid,msg)
    local coins = msg.coins
    --[[if not caishen_coins_map[uid] or caishen_coins_map[uid] ~= coins then
        errlog("put coins error",uid,caishen_coins_map[uid])
        return
    end]]
    if not caishen_coins_map[uid] or coins ~= caishen_coins_map[uid] then
        errlog("your param is error",uid,coins)
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.INPUT_ERROR})
        return false
    end

    if not check_have_enough_coins(uid,coins) then
        errlog("you have not enough coins",uid)
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.NOT_ENOUGH_COINS})
        return false
    end

    local res,ret_coins = pay_caishen_coins(uid,coins)
    if res == error_code.RSP_SUCESS then
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = res,award_coins = ret_coins})
    else
        send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = res})
    end
end


function handler.REQ_USE_MAGIC_PICTURE(uid,msg,game_session)
    local dst_id = msg.dst_id
    local picture_id = msg.picture_id
    if get_client_fd(uid) ~= game_session then
        errlog(uid,'invalid status',get_client_fd(uid),game_session)
        return
    end

    local src_player_info = get_player(uid)
    if not src_player_info then
        errlog(uid,"REQ_USE_MAGIC_PICTURE failed you are not a src_player_info")
        return
    end

    local dst_player_info = get_player(dst_id)
    if not dst_player_info then
        errlog(dst_id,"failed you are not a dst_player_info")
        send_to_gateway(uid,game_session,'table.RSP_USE_MAGIC_PICTURE',{
            result = error_code.TABLE_USE_MAGIC_PICTURE_MUST_SITDOWN
        })

        return
    end

    if not dst_player_info.position then
        errlog(uid,"player not have position")
        send_to_gateway(uid,game_session,'table.RSP_USE_MAGIC_PICTURE',{
            result = error_code.TABLE_USE_MAGIC_PICTURE_MUST_SITDOWN
        })

        return
    end

    send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{})

    notify_all('table.NTF_USE_MAGIC_PICTURE',{
        src_id = uid,
        dst_id = dst_id,
        picture_id = picture_id,
    })

    return true
end

function handler.REQ_SERVER_TIME(uid,msg,game_session)
    local now_sec, now_usec = util.get_now_time()
    local server_time = math_floor((now_sec * 1000) + (now_usec / 1000))
    send_to_gateway(uid,game_session,'fishing.RSP_SERVER_TIME',{server_time = server_time})
    return true
end

function handler.REQ_PERSONAL_INFO(uid,msg,game_session)
    local player_info = player_info_list[msg.uid]
    local ret = {}
    if player_info then
        local personal_info = {
            uid = player_info.uid,
            name = player_info.name,
            sex = player_info.sex,
            icon = player_info.icon,
            coins = player_info.coins,
            is_self = false,
            vip_level = player_info.vip_level or 0,
            icon_border = player_info.icon_border,
        }
        ret.personal_info = personal_info
        ret.is_set_down = player_info.position and true or false
        send_to_gateway(uid,game_session,'table.RSP_PERSONAL_INFO',ret)
    else
        send_to_gateway(uid,game_session,'table.RSP_PERSONAL_INFO',{result = error_code.NO_SUCH_PLAYER})
    end
    return true
end

--=================================table protocols=================
local function update_player_heartbeat(uid)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.last_ping_time = util.get_now_time()
    end
end

local function get_msg_module_name(msgid)
    local m = msgdef.id_to_name[msgid]
    if not m then return end
    return m[1],m[2]
end

function dispatch_client_message(game_session,uid,msg,size)
    local _,msgid,pbmsg,pbsize = proxypack.unpack_client_message(msg,size)
    local module,name = get_msg_module_name(msgid)

    if not module or not name then
        print('invalid msgid',msgid,module,name)
        return
    end

    local pbname = module .. '.' .. name
    local req_msg = pb.decode(pbname,pbmsg,pbsize)

--    dbglog(string.format('[%s]>>>>>player[%s] got a request[%s] content(%s)',skynet.address(skynet.self()),tostring(uid),pbname,tostring_r(req_msg)))

    local f = handler[name]
    if not f then
        errlog('unknown action',pbname)
        return
    end

    local ret = f(uid,req_msg,game_session)
    if not ret then
        errlog(string.format('failed to handle requrest(%s.%s)',module,name))
    end

    update_player_heartbeat(uid)
end

local function dispatch(_,_,game_session,uid,data)
    local msg,size = proxypack.pack_raw(data)
    local ok,errmsg = xpcall(dispatch_client_message,debug.traceback,game_session,uid,msg,size)
    skynet.trash(msg,size)
    if not ok then 
        errlog(errmsg)
    end
end

function handle_lua_req(session, source, action, ...)

    local f = internal[action]
    if f then
        skynet.retpack(f(...))
    else
        handler[action](...)
    end
end

function start()
    skynet.register_protocol {
        name = "client",
        id = skynet.PTYPE_CLIENT,
        unpack = skynet.unpack,
        dispatch = function(...) return dispatch(...) end
    }

    skynet.start(function()
        skynet.dispatch("lua",function(session,source,action,...)
            handle_lua_req(session, source, action, ...)
        end)

        -- sharedata.query("global_configs")
        -- global_configs = setmetatable({},{
        --     __index = function(t,k) 
        --         return sharedata.query("global_configs")[k]
        --     end
        -- })
        global_configs = setmetatable({},{
            __index = function(t,k) 
                --return sharedata.query("global_configs")[k]
                return sharedata.query(k)
            end
        })
        _G.global_configs = global_configs
    end)
end

return _ENV
